fdisk: many significant improvements and fixes to Sun label handling

1) Properly describe the exact layout and fields of the sun disk
   label.  Several fields were incorrectly mentioned and others
   wrongly sized.

2) Properly set the version, sane, and num_partitions fields.

   Because we weren't doing this, programs such as Solaris's format
   and the Solaris kernel itself refused to recognize our disk labels
   as valid.

3) Move SSWAP*() macros into fdisksunlabel.c as there is no reason
   for them to be exposed to the rest of fdisk.

4) Kill the sun_predefined_drives array hack and assosciated code.

   Instead size the disk and figure out the geometry properly just
   like the SGI and MSDOS partition handling do, by means of the
   HD_GETGEO ioctl() and disksize().

5) If the disk label read is found to not have the proper values
   set in version, sane, or num_partitions, fix them, recompute the
   label checksum, dirty the disk label, and let the user know what
   we did and that the fixed values will be written out if they 'w'.

   This gives users an easy way to fix up disk labels created by
   disk labelling programs which had this bug.

6) Create a sun_sys_getid() function so that fdisk.c does not need
   to reference the sun disk label details directly, just like the
   SGI code does.

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David Miller 2007-06-29 15:50:21 -07:00 committed by Karel Zak
parent eba338783e
commit 899736f12f
3 changed files with 329 additions and 372 deletions

View File

@ -470,7 +470,7 @@ xmenu(void) {
static int
get_sysid(int i) {
return (
sun_label ? sunlabel->infos[i].id :
sun_label ? sun_get_sysid(i) :
sgi_label ? sgi_get_sysid(i) :
ptes[i].part_table->sys_ind);
}
@ -1178,7 +1178,7 @@ get_partition(int warn, int max) {
if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
|| (sun_label &&
(!sunlabel->partitions[i].num_sectors ||
!sunlabel->infos[i].id))
!sunlabel->part_tags[i].tag))
|| (sgi_label && (!sgi_get_num_sectors(i)))
)
fprintf(stderr,
@ -1400,7 +1400,7 @@ change_sysid(void) {
}
if (sys < 256) {
if (sun_label && i == 2 && sys != WHOLE_DISK)
if (sun_label && i == 2 && sys != SUN_TAG_BACKUP)
printf(_("Consider leaving partition 3 "
"as Whole disk (5),\n"
"as SunOS/Solaris expects it and "
@ -2614,7 +2614,7 @@ main(int argc, char **argv) {
toggle_active(get_partition(1, partitions));
else if (sun_label)
toggle_sunflags(get_partition(1, partitions),
0x01);
SUN_FLAG_UNMNT);
else if (sgi_label)
sgi_set_bootpartition(
get_partition(1, partitions));
@ -2638,7 +2638,7 @@ main(int argc, char **argv) {
toggle_dos_compatibility_flag();
else if (sun_label)
toggle_sunflags(get_partition(1, partitions),
0x10);
SUN_FLAG_RONLY);
else if (sgi_label)
sgi_set_swappartition(
get_partition(1, partitions));

View File

@ -36,25 +36,23 @@ static int other_endian = 0;
static int scsi_disk = 0;
static int floppy = 0;
#define LINUX_SWAP 0x82
#define LINUX_NATIVE 0x83
struct systypes sun_sys_types[] = {
{0, N_("Empty")},
{1, N_("Boot")},
{2, N_("SunOS root")},
{SUNOS_SWAP, N_("SunOS swap")},
{4, N_("SunOS usr")},
{WHOLE_DISK, N_("Whole disk")},
{6, N_("SunOS stand")},
{7, N_("SunOS var")},
{8, N_("SunOS home")},
{LINUX_SWAP, N_("Linux swap")},
{LINUX_NATIVE, N_("Linux native")},
{0x8e, N_("Linux LVM")},
{0xfd, N_("Linux raid autodetect")},/* New (2.2.x) raid partition
with autodetect using
persistent superblock */
{SUN_TAG_UNASSIGNED, N_("Unassigned")},
{SUN_TAG_BOOT, N_("Boot")},
{SUN_TAG_ROOT, N_("SunOS root")},
{SUN_TAG_SWAP, N_("SunOS swap")},
{SUN_TAG_USR, N_("SunOS usr")},
{SUN_TAG_BACKUP, N_("Whole disk")},
{SUN_TAG_STAND, N_("SunOS stand")},
{SUN_TAG_VAR, N_("SunOS var")},
{SUN_TAG_HOME, N_("SunOS home")},
{SUN_TAG_ALTSCTR, N_("SunOS alt sectors")},
{SUN_TAG_CACHE, N_("SunOS cachefs")},
{SUN_TAG_RESERVED, N_("SunOS reserved")},
{SUN_TAG_LINUX_SWAP, N_("Linux swap")},
{SUN_TAG_LINUX_NATIVE, N_("Linux native")},
{SUN_TAG_LINUX_LVM, N_("Linux LVM")},
{SUN_TAG_LINUX_RAID, N_("Linux raid autodetect")},
{ 0, NULL }
};
@ -65,10 +63,10 @@ static inline __u32 __swap32(__u32 x) {
return (((__u32)(x) & 0xFF) << 24) | (((__u32)(x) & 0xFF00) << 8) | (((__u32)(x) & 0xFF0000) >> 8) | (((__u32)(x) & 0xFF000000) >> 24);
}
int
get_num_sectors(struct sun_partition p) {
return SSWAP32(p.num_sectors);
}
#define SSWAP16(x) (other_endian ? __swap16(x) \
: (__u16)(x))
#define SSWAP32(x) (other_endian ? __swap32(x) \
: (__u32)(x))
#ifndef IDE0_MAJOR
#define IDE0_MAJOR 3
@ -76,7 +74,8 @@ get_num_sectors(struct sun_partition p) {
#ifndef IDE1_MAJOR
#define IDE1_MAJOR 22
#endif
void guess_device_type(int fd) {
void guess_device_type(int fd)
{
struct stat bootstat;
if (fstat (fd, &bootstat) < 0) {
@ -97,9 +96,10 @@ void guess_device_type(int fd) {
}
}
static void
set_sun_partition(int i, unsigned int start, unsigned int stop, int sysid) {
sunlabel->infos[i].id = sysid;
static void set_sun_partition(int i, __u32 start, __u32 stop, __u16 sysid)
{
sunlabel->part_tags[i].tag = SSWAP16(sysid);
sunlabel->part_tags[i].flag = SSWAP16(0);
sunlabel->partitions[i].start_cylinder =
SSWAP32(start / (heads * sectors));
sunlabel->partitions[i].num_sectors =
@ -107,15 +107,15 @@ set_sun_partition(int i, unsigned int start, unsigned int stop, int sysid) {
set_changed(i);
}
void
sun_nolabel(void) {
void sun_nolabel(void)
{
sun_label = 0;
sunlabel->magic = 0;
partitions = 4;
}
int
check_sun_label(void) {
int check_sun_label(void)
{
unsigned short *ush;
int csum;
@ -126,133 +126,67 @@ check_sun_label(void) {
return 0;
}
other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
ush = ((unsigned short *) (sunlabel + 1)) - 1;
for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
for (csum = 0; ush >= (unsigned short *)sunlabel;)
csum ^= *ush--;
if (csum) {
fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
"Probably you'll have to set all the values,\n"
"e.g. heads, sectors, cylinders and partitions\n"
"or force a fresh label (s command in main menu)\n"));
} else {
heads = SSWAP16(sunlabel->ntrks);
int need_fixing = 0;
heads = SSWAP16(sunlabel->nhead);
cylinders = SSWAP16(sunlabel->ncyl);
sectors = SSWAP16(sunlabel->nsect);
if (sunlabel->version != SSWAP32(SUN_LABEL_VERSION)) {
fprintf(stderr,_("Detected sun disklabel with wrong version [0x%08x].\n"),
sunlabel->version);
need_fixing = 1;
}
if (sunlabel->sanity != SSWAP32(SUN_LABEL_SANE)) {
fprintf(stderr,_("Detected sun disklabel with wrong sanity [0x%08x].\n"),
sunlabel->sanity);
need_fixing = 1;
}
if (sunlabel->num_partitions != SSWAP16(SUN_NUM_PARTITIONS)) {
fprintf(stderr,_("Detected sun disklabel with wrong num_partitions [%u].\n"),
sunlabel->num_partitions);
need_fixing = 1;
}
if (need_fixing) {
fprintf(stderr, _("Warning: Wrong values need to be "
"fixed up and will be corrected "
"by w(rite)\n"));
sunlabel->version = SSWAP32(SUN_LABEL_VERSION);
sunlabel->sanity = SSWAP32(SUN_LABEL_SANE);
sunlabel->num_partitions = SSWAP16(SUN_NUM_PARTITIONS);
ush = (unsigned short *)sunlabel;
csum = 0;
while(ush < (unsigned short *)(&sunlabel->cksum))
csum ^= *ush++;
sunlabel->cksum = csum;
set_changed(0);
}
}
update_units();
sun_label = 1;
partitions = 8;
partitions = SUN_NUM_PARTITIONS;
return 1;
}
struct sun_predefined_drives {
char *vendor;
char *model;
unsigned short sparecyl;
unsigned short ncyl;
unsigned short nacyl;
unsigned short pcylcount;
unsigned short ntrks;
unsigned short nsect;
unsigned short rspeed;
} sun_drives[] = {
{"Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
{"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
{"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
{"IBM","DPES-31080",0,4901,2,4903,4,108,5400},
{"IBM","DORS-32160",0,1015,2,1017,67,62,5400},
{"IBM","DNES-318350",0,11199,2,11474,10,320,7200},
{"SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
{"","SUN0104",1,974,2,1019,6,35,3662},
{"","SUN0207",4,1254,2,1272,9,36,3600},
{"","SUN0327",3,1545,2,1549,9,46,3600},
{"","SUN0340",0,1538,2,1544,6,72,4200},
{"","SUN0424",2,1151,2,2500,9,80,4400},
{"","SUN0535",0,1866,2,2500,7,80,5400},
{"","SUN0669",5,1614,2,1632,15,54,3600},
{"","SUN1.0G",5,1703,2,1931,15,80,3597},
{"","SUN1.05",0,2036,2,2038,14,72,5400},
{"","SUN1.3G",6,1965,2,3500,17,80,5400},
{"","SUN2.1G",0,2733,2,3500,19,80,5400},
{"IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
};
static struct sun_predefined_drives *
sun_autoconfigure_scsi(void) {
struct sun_predefined_drives *p = NULL;
#ifdef SCSI_IOCTL_GET_IDLUN
unsigned int id[2];
char buffer[2048];
char buffer2[2048];
FILE *pfd;
char *vendor;
char *model;
char *q;
int i;
if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
sprintf(buffer,
"Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
#if 0
((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
#else
/* This is very wrong (works only if you have one HBA),
but I haven't found a way how to get hostno
from the current kernel */
0,
#endif
(id[0]>>16)&0xff,
id[0]&0xff,
(id[0]>>8)&0xff);
pfd = fopen("/proc/scsi/scsi","r");
if (pfd) {
while (fgets(buffer2,2048,pfd)) {
if (!strcmp(buffer, buffer2)) {
if (fgets(buffer2,2048,pfd)) {
q = strstr(buffer2,"Vendor: ");
if (q) {
q += 8;
vendor = q;
q = strstr(q," ");
*q++ = 0; /* truncate vendor name */
q = strstr(q,"Model: ");
if (q) {
*q = 0;
q += 7;
model = q;
q = strstr(q," Rev: ");
if (q) {
*q = 0;
for (i = 0; i < SIZE(sun_drives); i++) {
if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
continue;
if (!strstr(model, sun_drives[i].model))
continue;
printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
p = sun_drives + i;
break;
}
}
}
}
}
break;
}
}
fclose(pfd);
}
}
#endif
return p;
}
void create_sunlabel(void)
{
struct hd_geometry geometry;
unsigned long long llsectors, llcyls;
unsigned int ndiv;
int i;
unsigned char c;
struct sun_predefined_drives *p = NULL;
int res, sec_fac;
fprintf(stderr,
_("Building a new sun disklabel. Changes will remain in memory only,\n"
@ -265,116 +199,70 @@ void create_sunlabel(void)
#endif
memset(MBRbuffer, 0, sizeof(MBRbuffer));
sunlabel->magic = SSWAP16(SUN_LABEL_MAGIC);
if (!floppy) {
puts(_("Drive type\n"
" ? auto configure\n"
" 0 custom (with hardware detected defaults)"));
for (i = 0; i < SIZE(sun_drives); i++) {
printf(" %c %s%s%s\n",
i + 'a', sun_drives[i].vendor,
(*sun_drives[i].vendor) ? " " : "",
sun_drives[i].model);
}
for (;;) {
c = read_char(_("Select type (? for auto, 0 for custom): "));
if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
p = sun_drives + c - 'a';
break;
} else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
p = sun_drives + c - 'A';
break;
} else if (c == '0') {
break;
} else if (c == '?' && scsi_disk) {
p = sun_autoconfigure_scsi();
if (!p)
printf(_("Autoconfigure failed.\n"));
else
break;
}
}
}
if (!p || floppy) {
if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
sunlabel->sanity = SSWAP32(SUN_LABEL_SANE);
sunlabel->version = SSWAP32(SUN_LABEL_VERSION);
sunlabel->num_partitions = SSWAP16(SUN_NUM_PARTITIONS);
res = disksize(fd, &llsectors);
sec_fac = sector_size / 512;
if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
heads = geometry.heads;
sectors = geometry.sectors;
cylinders = geometry.cylinders;
} else {
heads = 0;
sectors = 0;
cylinders = 0;
}
if (floppy) {
sunlabel->nacyl = 0;
sunlabel->pcylcount = SSWAP16(cylinders);
sunlabel->rspeed = SSWAP16(300);
sunlabel->ilfact = SSWAP16(1);
sunlabel->sparecyl = 0;
} else {
heads = read_int(1,heads,1024,0,_("Heads"));
sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
if (cylinders)
cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
else
cylinders = read_int(1,0,65535,0,_("Cylinders"));
sunlabel->nacyl =
SSWAP16(read_int(0,2,65535,0,
_("Alternate cylinders")));
sunlabel->pcylcount =
SSWAP16(read_int(0,cylinders+SSWAP16(sunlabel->nacyl),
65535,0,_("Physical cylinders")));
sunlabel->rspeed =
SSWAP16(read_int(1,5400,100000,0,
_("Rotation speed (rpm)")));
sunlabel->ilfact =
SSWAP16(read_int(1,1,32,0,_("Interleave factor")));
sunlabel->sparecyl =
SSWAP16(read_int(0,0,sectors,0,
_("Extra sectors per cylinder")));
}
if (res == 0) {
llcyls = llsectors / (heads * sectors * sec_fac);
cylinders = llcyls;
if (cylinders != llcyls)
cylinders = ~0;
} else {
cylinders = geometry.cylinders;
fprintf(stderr,
_("Warning: BLKGETSIZE ioctl failed on %s. "
"Using geometry cylinder value of %d.\n"
"This value may be truncated for devices"
" > 33.8 GB.\n"), disk_device, cylinders);
}
} else {
sunlabel->sparecyl = SSWAP16(p->sparecyl);
sunlabel->ncyl = SSWAP16(p->ncyl);
sunlabel->nacyl = SSWAP16(p->nacyl);
sunlabel->pcylcount = SSWAP16(p->pcylcount);
sunlabel->ntrks = SSWAP16(p->ntrks);
sunlabel->nsect = SSWAP16(p->nsect);
sunlabel->rspeed = SSWAP16(p->rspeed);
sunlabel->ilfact = SSWAP16(1);
cylinders = p->ncyl;
heads = p->ntrks;
sectors = p->nsect;
puts(_("You may change all the disk params from the x menu"));
heads = read_int(1,1,1024,0,_("Heads"));
sectors = read_int(1,1,1024,0,_("Sectors/track"));
cylinders = read_int(1,1,65535,0,_("Cylinders"));
}
snprintf(sunlabel->info, sizeof(sunlabel->info),
"%s%s%s cyl %d alt %d hd %d sec %llu",
p ? p->vendor : "", (p && *p->vendor) ? " " : "",
p ? p->model
: (floppy ? _("3,5\" floppy") : _("Linux custom")),
cylinders, SSWAP16(sunlabel->nacyl), heads, sectors);
sunlabel->acyl = SSWAP16(2);
sunlabel->pcyl = SSWAP16(cylinders);
sunlabel->ncyl = SSWAP16(cylinders - 2);
sunlabel->rpm = SSWAP16(5400);
sunlabel->intrlv = SSWAP16(1);
sunlabel->apc = SSWAP16(0);
sunlabel->ntrks = SSWAP16(heads);
sunlabel->nhead = SSWAP16(heads);
sunlabel->nsect = SSWAP16(sectors);
sunlabel->ncyl = SSWAP16(cylinders);
if (floppy)
set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
else {
if (cylinders * heads * sectors >= 150 * 2048) {
snprintf(sunlabel->label_id, sizeof(sunlabel->label_id),
"Linux cyl %d alt %d hd %d sec %llu",
cylinders, SSWAP16(sunlabel->acyl), heads, sectors);
if (cylinders * heads * sectors >= 150 * 2048) {
ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
} else
} else
ndiv = cylinders * 2 / 3;
set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
sunlabel->infos[1].flags |= 0x01; /* Not mountable */
}
set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
set_sun_partition(0, 0, ndiv * heads * sectors,
SUN_TAG_LINUX_NATIVE);
set_sun_partition(1, ndiv * heads * sectors,
cylinders * heads * sectors,
SUN_TAG_LINUX_SWAP);
sunlabel->part_tags[1].flag |= SSWAP16(SUN_FLAG_UNMNT);
set_sun_partition(2, 0, cylinders * heads * sectors, SUN_TAG_BACKUP);
{
unsigned short *ush = (unsigned short *)sunlabel;
unsigned short csum = 0;
while(ush < (unsigned short *)(&sunlabel->csum))
while(ush < (unsigned short *)(&sunlabel->cksum))
csum ^= *ush++;
sunlabel->csum = csum;
sunlabel->cksum = csum;
}
set_all_unchanged();
@ -382,24 +270,32 @@ void create_sunlabel(void)
set_changed(0);
}
void
toggle_sunflags(int i, unsigned char mask) {
if (sunlabel->infos[i].flags & mask)
sunlabel->infos[i].flags &= ~mask;
else sunlabel->infos[i].flags |= mask;
void toggle_sunflags(int i, __u16 mask)
{
struct sun_tag_flag *p = &sunlabel->part_tags[i];
p->flag ^= SSWAP16(mask);
set_changed(i);
}
static void
fetch_sun(unsigned int *starts, unsigned int *lens, unsigned int *start, unsigned int *stop) {
static void fetch_sun(__u32 *starts, __u32 *lens, __u32 *start, __u32 *stop)
{
int i, continuous = 1;
*start = 0; *stop = cylinders * heads * sectors;
*start = 0;
*stop = cylinders * heads * sectors;
for (i = 0; i < partitions; i++) {
if (sunlabel->partitions[i].num_sectors
&& sunlabel->infos[i].id
&& sunlabel->infos[i].id != WHOLE_DISK) {
starts[i] = SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
lens[i] = SSWAP32(sunlabel->partitions[i].num_sectors);
struct sun_partition *part = &sunlabel->partitions[i];
struct sun_tag_flag *tag = &sunlabel->part_tags[i];
if (part->num_sectors &&
tag->tag != SSWAP16(SUN_TAG_UNASSIGNED) &&
tag->tag != SSWAP16(SUN_TAG_BACKUP)) {
starts[i] = (SSWAP32(part->start_cylinder) *
heads * sectors);
lens[i] = SSWAP32(part->num_sectors);
if (continuous) {
if (starts[i] == *start)
*start += lens[i];
@ -419,24 +315,29 @@ fetch_sun(unsigned int *starts, unsigned int *lens, unsigned int *start, unsigne
static unsigned int *verify_sun_starts;
static int
verify_sun_cmp(int *a, int *b) {
if (*a == -1) return 1;
if (*b == -1) return -1;
if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
static int verify_sun_cmp(int *a, int *b)
{
if (*a == -1)
return 1;
if (*b == -1)
return -1;
if (verify_sun_starts[*a] > verify_sun_starts[*b])
return 1;
return -1;
}
void
verify_sun(void) {
unsigned int starts[8], lens[8], start, stop;
void verify_sun(void)
{
__u32 starts[SUN_NUM_PARTITIONS], lens[SUN_NUM_PARTITIONS], start, stop;
int i,j,k,starto,endo;
int array[8];
int array[SUN_NUM_PARTITIONS];
verify_sun_starts = starts;
fetch_sun(starts,lens,&start,&stop);
fetch_sun(starts, lens, &start, &stop);
for (k = 0; k < 7; k++) {
for (i = 0; i < 8; i++) {
for (i = 0; i < SUN_NUM_PARTITIONS; i++) {
if (k && (lens[i] % (heads * sectors))) {
printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
}
@ -466,7 +367,7 @@ verify_sun(void) {
}
}
}
for (i = 0; i < 8; i++) {
for (i = 0; i < SUN_NUM_PARTITIONS; i++) {
if (lens[i])
array[i] = i;
else
@ -480,31 +381,35 @@ verify_sun(void) {
}
stop = cylinders * heads * sectors;
if (starts[array[0]])
printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
printf(_("Unused gap - sectors 0-%d\n"), starts[array[0]]);
for (i = 0; i < 7 && array[i+1] != -1; i++) {
printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
printf(_("Unused gap - sectors %d-%d\n"),
(starts[array[i]] + lens[array[i]]),
starts[array[i+1]]);
}
start = starts[array[i]]+lens[array[i]];
start = (starts[array[i]] + lens[array[i]]);
if (start < stop)
printf(_("Unused gap - sectors %d-%d\n"),start,stop);
printf(_("Unused gap - sectors %d-%d\n"), start, stop);
}
void
add_sun_partition(int n, int sys) {
unsigned int start, stop, stop2;
unsigned int starts[8], lens[8];
void add_sun_partition(int n, int sys)
{
__u32 starts[SUN_NUM_PARTITIONS], lens[SUN_NUM_PARTITIONS];
struct sun_partition *part = &sunlabel->partitions[n];
struct sun_tag_flag *tag = &sunlabel->part_tags[n];
__u32 start, stop, stop2;
int whole_disk = 0;
char mesg[256];
int i, first, last;
if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
if (part->num_sectors && tag->tag != SSWAP16(SUN_TAG_UNASSIGNED)) {
printf(_("Partition %d is already defined. Delete "
"it before re-adding it.\n"), n + 1);
return;
}
fetch_sun(starts,lens,&start,&stop);
fetch_sun(starts, lens, &start, &stop);
if (stop <= start) {
if (n == 2)
whole_disk = 1;
@ -600,29 +505,37 @@ and is of type `Whole disk'\n");
} else if (!whole_disk && last > stop)
last = stop;
if (whole_disk) sys = WHOLE_DISK;
if (whole_disk)
sys = SUN_TAG_BACKUP;
set_sun_partition(n, first, last, sys);
}
void
sun_delete_partition(int i) {
void sun_delete_partition(int i)
{
struct sun_partition *part = &sunlabel->partitions[i];
struct sun_tag_flag *tag = &sunlabel->part_tags[i];
unsigned int nsec;
if (i == 2 && sunlabel->infos[i].id == WHOLE_DISK &&
!sunlabel->partitions[i].start_cylinder &&
(nsec = SSWAP32(sunlabel->partitions[i].num_sectors))
if (i == 2 &&
tag->tag == SSWAP16(SUN_TAG_BACKUP) &&
!part->start_cylinder &&
(nsec = SSWAP32(part->num_sectors))
== heads * sectors * cylinders)
printf(_("If you want to maintain SunOS/Solaris compatibility, "
"consider leaving this\n"
"partition as Whole disk (5), starting at 0, with %u "
"sectors\n"), nsec);
sunlabel->infos[i].id = 0;
sunlabel->partitions[i].num_sectors = 0;
tag->tag = SSWAP16(SUN_TAG_UNASSIGNED);
part->num_sectors = 0;
}
void
sun_change_sysid(int i, int sys) {
if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
void sun_change_sysid(int i, __u16 sys)
{
struct sun_partition *part = &sunlabel->partitions[i];
struct sun_tag_flag *tag = &sunlabel->part_tags[i];
if (sys == SUN_TAG_LINUX_SWAP && !part->start_cylinder) {
read_chars(
_("It is highly recommended that the partition at offset 0\n"
"is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
@ -633,22 +546,22 @@ sun_change_sysid(int i, int sys) {
return;
}
switch (sys) {
case SUNOS_SWAP:
case LINUX_SWAP:
case SUN_TAG_SWAP:
case SUN_TAG_LINUX_SWAP:
/* swaps are not mountable by default */
sunlabel->infos[i].flags |= 0x01;
tag->flag |= SSWAP16(SUN_FLAG_UNMNT);
break;
default:
/* assume other types are mountable;
user can change it anyway */
sunlabel->infos[i].flags &= ~0x01;
tag->flag &= ~SSWAP16(SUN_FLAG_UNMNT);
break;
}
sunlabel->infos[i].id = sys;
tag->tag = SSWAP16(sys);
}
void
sun_list_table(int xtra) {
void sun_list_table(int xtra)
{
int i, w;
char *type;
@ -658,14 +571,16 @@ sun_list_table(int xtra) {
_("\nDisk %s (Sun disk label): %d heads, %llu sectors, %d rpm\n"
"%d cylinders, %d alternate cylinders, %d physical cylinders\n"
"%d extra sects/cyl, interleave %d:1\n"
"%s\n"
"Label ID: %s\n"
"Volume ID: %s\n"
"Units = %s of %d * 512 bytes\n\n"),
disk_device, heads, sectors, SSWAP16(sunlabel->rspeed),
cylinders, SSWAP16(sunlabel->nacyl),
SSWAP16(sunlabel->pcylcount),
SSWAP16(sunlabel->sparecyl),
SSWAP16(sunlabel->ilfact),
(char *)sunlabel,
disk_device, heads, sectors, SSWAP16(sunlabel->rpm),
cylinders, SSWAP16(sunlabel->acyl),
SSWAP16(sunlabel->pcyl),
SSWAP16(sunlabel->apc),
SSWAP16(sunlabel->intrlv),
sunlabel->label_id,
sunlabel->volume_id,
str_units(PLURAL), units_per_sector);
else
printf(
@ -677,74 +592,82 @@ sun_list_table(int xtra) {
printf(_("%*s Flag Start End Blocks Id System\n"),
w + 1, _("Device"));
for (i = 0 ; i < partitions; i++) {
if (sunlabel->partitions[i].num_sectors) {
__u32 start = SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
__u32 len = SSWAP32(sunlabel->partitions[i].num_sectors);
struct sun_partition *part = &sunlabel->partitions[i];
struct sun_tag_flag *tag = &sunlabel->part_tags[i];
if (part->num_sectors) {
__u32 start = SSWAP32(part->start_cylinder) * heads * sectors;
__u32 len = SSWAP32(part->num_sectors);
printf(
"%s %c%c %9ld %9ld %9ld%c %2x %s\n",
/* device */ partname(disk_device, i+1, w),
/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',
(sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
/* flags */ (tag->flag & SSWAP16(SUN_FLAG_UNMNT)) ? 'u' : ' ',
(tag->flag & SSWAP16(SUN_FLAG_RONLY)) ? 'r' : ' ',
/* start */ (long) scround(start),
/* end */ (long) scround(start+len),
/* odd flag on end */ (long) len / 2, len & 1 ? '+' : ' ',
/* type id */ sunlabel->infos[i].id,
/* type name */ (type = partition_type(sunlabel->infos[i].id))
/* type id */ SSWAP16(tag->tag),
/* type name */ (type = partition_type(SSWAP16(tag->tag)))
? type : _("Unknown"));
}
}
}
void
sun_set_alt_cyl(void) {
sunlabel->nacyl =
SSWAP16(read_int(0,SSWAP16(sunlabel->nacyl), 65535, 0,
void sun_set_alt_cyl(void)
{
sunlabel->acyl =
SSWAP16(read_int(0,SSWAP16(sunlabel->acyl), 65535, 0,
_("Number of alternate cylinders")));
}
void
sun_set_ncyl(int cyl) {
void sun_set_ncyl(int cyl)
{
sunlabel->ncyl = SSWAP16(cyl);
}
void
sun_set_xcyl(void) {
sunlabel->sparecyl =
SSWAP16(read_int(0, SSWAP16(sunlabel->sparecyl), sectors, 0,
void sun_set_xcyl(void)
{
sunlabel->apc =
SSWAP16(read_int(0, SSWAP16(sunlabel->apc), sectors, 0,
_("Extra sectors per cylinder")));
}
void
sun_set_ilfact(void) {
sunlabel->ilfact =
SSWAP16(read_int(1, SSWAP16(sunlabel->ilfact), 32, 0,
void sun_set_ilfact(void)
{
sunlabel->intrlv =
SSWAP16(read_int(1, SSWAP16(sunlabel->intrlv), 32, 0,
_("Interleave factor")));
}
void
sun_set_rspeed(void) {
sunlabel->rspeed =
SSWAP16(read_int(1, SSWAP16(sunlabel->rspeed), 100000, 0,
void sun_set_rspeed(void)
{
sunlabel->rpm =
SSWAP16(read_int(1, SSWAP16(sunlabel->rpm), 100000, 0,
_("Rotation speed (rpm)")));
}
void
sun_set_pcylcount(void) {
sunlabel->pcylcount =
SSWAP16(read_int(0, SSWAP16(sunlabel->pcylcount), 65535, 0,
void sun_set_pcylcount(void)
{
sunlabel->pcyl =
SSWAP16(read_int(0, SSWAP16(sunlabel->pcyl), 65535, 0,
_("Number of physical cylinders")));
}
void
sun_write_table(void) {
void sun_write_table(void)
{
unsigned short *ush = (unsigned short *)sunlabel;
unsigned short csum = 0;
while(ush < (unsigned short *)(&sunlabel->csum))
while(ush < (unsigned short *)(&sunlabel->cksum))
csum ^= *ush++;
sunlabel->csum = csum;
sunlabel->cksum = csum;
if (lseek(fd, 0, SEEK_SET) < 0)
fatal(unable_to_seek);
if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
fatal(unable_to_write);
}
int sun_get_sysid(int i)
{
return SSWAP16(sunlabel->part_tags[i].tag);
}

View File

@ -3,53 +3,86 @@
#include <linux/types.h> /* for __u16, __u32 */
typedef struct {
unsigned char info[128]; /* Informative text string */
unsigned char spare0[14];
struct sun_info {
unsigned char spare1;
unsigned char id;
unsigned char spare2;
unsigned char flags;
} infos[8];
unsigned char spare1[246]; /* Boot information etc. */
unsigned short rspeed; /* Disk rotational speed */
unsigned short pcylcount; /* Physical cylinder count */
unsigned short sparecyl; /* extra sects per cylinder */
unsigned char spare2[4]; /* More magic... */
unsigned short ilfact; /* Interleave factor */
unsigned short ncyl; /* Data cylinder count */
unsigned short nacyl; /* Alt. cylinder count */
unsigned short ntrks; /* Tracks per cylinder */
unsigned short nsect; /* Sectors per track */
unsigned char spare3[4]; /* Even more magic... */
struct sun_partition {
__u32 start_cylinder;
__u32 num_sectors;
} partitions[8];
unsigned short magic; /* Magic number */
unsigned short csum; /* Label xor'd checksum */
} sun_partition;
struct sun_partition {
__u32 start_cylinder;
__u32 num_sectors;
};
struct sun_tag_flag {
__u16 tag;
#define SUN_TAG_UNASSIGNED 0x00 /* Unassigned partition */
#define SUN_TAG_BOOT 0x01 /* Boot partition */
#define SUN_TAG_ROOT 0x02 /* Root filesystem */
#define SUN_TAG_SWAP 0x03 /* Swap partition */
#define SUN_TAG_USR 0x04 /* /usr filesystem */
#define SUN_TAG_BACKUP 0x05 /* Full-disk slice */
#define SUN_TAG_STAND 0x06 /* Stand partition */
#define SUN_TAG_VAR 0x07 /* /var filesystem */
#define SUN_TAG_HOME 0x08 /* /home filesystem */
#define SUN_TAG_ALTSCTR 0x09 /* Alt sector partition */
#define SUN_TAG_CACHE 0x0a /* Cachefs partition */
#define SUN_TAG_RESERVED 0x0b /* SMI reserved data */
#define SUN_TAG_LINUX_SWAP 0x82 /* Linux SWAP */
#define SUN_TAG_LINUX_NATIVE 0x83 /* Linux filesystem */
#define SUN_TAG_LINUX_LVM 0x8e /* Linux LVM */
#define SUN_TAG_LINUX_RAID 0xfd /* LInux RAID */
__u16 flag;
#define SUN_FLAG_UNMNT 0x01 /* Unmountable partition*/
#define SUN_FLAG_RONLY 0x10 /* Read only */
};
#define SUN_LABEL_SIZE 512
#define SUN_LABEL_ID_SIZE 128
#define SUN_VOLUME_ID_SIZE 8
#define SUN_LABEL_VERSION 0x00000001
#define SUN_LABEL_SANE 0x600ddeee
#define SUN_NUM_PARTITIONS 8
struct sun_disk_label {
char label_id[SUN_LABEL_ID_SIZE];
__u32 version;
char volume_id[SUN_VOLUME_ID_SIZE];
__u16 num_partitions;
struct sun_tag_flag part_tags[SUN_NUM_PARTITIONS];
__u32 bootinfo[3];
__u32 sanity;
__u32 resv[10];
__u32 part_timestamps[SUN_NUM_PARTITIONS];
__u32 write_reinstruct;
__u32 read_reinstruct;
__u8 pad[148];
__u16 rpm;
__u16 pcyl;
__u16 apc;
__u16 resv1;
__u16 resv2;
__u16 intrlv;
__u16 ncyl;
__u16 acyl;
__u16 nhead;
__u16 nsect;
__u16 resv3;
__u16 resv4;
struct sun_partition partitions[SUN_NUM_PARTITIONS];
__u16 magic;
__u16 cksum;
};
#define SUN_LABEL_MAGIC 0xDABE
#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
#define sunlabel ((struct sun_disk_label *)MBRbuffer)
#define SUN_LABEL_MAGIC 0xDABE
#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
#define sunlabel ((sun_partition *)MBRbuffer)
#define SSWAP16(x) (other_endian ? __swap16(x) \
: (__u16)(x))
#define SSWAP32(x) (other_endian ? __swap32(x) \
: (__u32)(x))
/* fdisksunlabel.c */
#define SUNOS_SWAP 3
#define WHOLE_DISK 5
extern struct systypes sun_sys_types[];
extern int get_num_sectors(struct sun_partition p);
extern void guess_device_type(int fd);
extern int check_sun_label(void);
extern void sun_nolabel(void);
extern void create_sunlabel(void);
extern void sun_delete_partition(int i);
extern void sun_change_sysid(int i, int sys);
extern void sun_change_sysid(int i, __u16 sys);
extern void sun_list_table(int xtra);
extern void verify_sun(void);
extern void add_sun_partition(int n, int sys);
@ -60,6 +93,7 @@ extern void sun_set_xcyl(void);
extern void sun_set_ilfact(void);
extern void sun_set_rspeed(void);
extern void sun_set_pcylcount(void);
extern void toggle_sunflags(int i, unsigned char mask);
extern void toggle_sunflags(int i, __u16 mask);
extern int sun_get_sysid(int i);
#endif /* FDISK_SUN_LABEL_H */