1/* 2 * fdisk_sun.c 3 * 4 * I think this is mostly, or entirely, due to 5 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996 6 * 7 * Merged with fdisk for other architectures, aeb, June 1998. 8 * 9 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br> 10 * Internationalization 11 * 12 * Licensed under GPLv2, see file LICENSE in this tarball for details. 13 */ 14 15#if ENABLE_FEATURE_SUN_LABEL 16 17#define SUNOS_SWAP 3 18#define SUN_WHOLE_DISK 5 19 20#define SUN_LABEL_MAGIC 0xDABE 21#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA 22#define SUN_SSWAP16(x) (sun_other_endian ? fdisk_swap16(x) : (uint16_t)(x)) 23#define SUN_SSWAP32(x) (sun_other_endian ? fdisk_swap32(x) : (uint32_t)(x)) 24 25/* Copied from linux/major.h */ 26#define FLOPPY_MAJOR 2 27 28#define SCSI_IOCTL_GET_IDLUN 0x5382 29 30static smallint sun_other_endian; 31static smallint scsi_disk; 32static smallint floppy; 33 34#ifndef IDE0_MAJOR 35#define IDE0_MAJOR 3 36#endif 37#ifndef IDE1_MAJOR 38#define IDE1_MAJOR 22 39#endif 40 41static void 42guess_device_type(void) 43{ 44 struct stat bootstat; 45 46 if (fstat(dev_fd, &bootstat) < 0) { 47 scsi_disk = 0; 48 floppy = 0; 49 } else if (S_ISBLK(bootstat.st_mode) 50 && (major(bootstat.st_rdev) == IDE0_MAJOR || 51 major(bootstat.st_rdev) == IDE1_MAJOR)) { 52 scsi_disk = 0; 53 floppy = 0; 54 } else if (S_ISBLK(bootstat.st_mode) 55 && major(bootstat.st_rdev) == FLOPPY_MAJOR) { 56 scsi_disk = 0; 57 floppy = 1; 58 } else { 59 scsi_disk = 1; 60 floppy = 0; 61 } 62} 63 64static const char *const sun_sys_types[] = { 65 "\x00" "Empty" , /* 0 */ 66 "\x01" "Boot" , /* 1 */ 67 "\x02" "SunOS root" , /* 2 */ 68 "\x03" "SunOS swap" , /* SUNOS_SWAP */ 69 "\x04" "SunOS usr" , /* 4 */ 70 "\x05" "Whole disk" , /* SUN_WHOLE_DISK */ 71 "\x06" "SunOS stand" , /* 6 */ 72 "\x07" "SunOS var" , /* 7 */ 73 "\x08" "SunOS home" , /* 8 */ 74 "\x82" "Linux swap" , /* LINUX_SWAP */ 75 "\x83" "Linux native", /* LINUX_NATIVE */ 76 "\x8e" "Linux LVM" , /* 0x8e */ 77/* New (2.2.x) raid partition with autodetect using persistent superblock */ 78 "\xfd" "Linux raid autodetect", /* 0xfd */ 79 NULL 80}; 81 82 83static void 84set_sun_partition(int i, unsigned start, unsigned stop, int sysid) 85{ 86 sunlabel->infos[i].id = sysid; 87 sunlabel->partitions[i].start_cylinder = 88 SUN_SSWAP32(start / (g_heads * g_sectors)); 89 sunlabel->partitions[i].num_sectors = 90 SUN_SSWAP32(stop - start); 91 set_changed(i); 92} 93 94static int 95check_sun_label(void) 96{ 97 unsigned short *ush; 98 int csum; 99 100 if (sunlabel->magic != SUN_LABEL_MAGIC 101 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED 102 ) { 103 current_label_type = LABEL_DOS; 104 sun_other_endian = 0; 105 return 0; 106 } 107 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED); 108 ush = ((unsigned short *) (sunlabel + 1)) - 1; 109 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--; 110 if (csum) { 111 printf("Detected sun disklabel with wrong checksum.\n" 112"Probably you'll have to set all the values,\n" 113"e.g. heads, sectors, cylinders and partitions\n" 114"or force a fresh label (s command in main menu)\n"); 115 } else { 116 g_heads = SUN_SSWAP16(sunlabel->ntrks); 117 g_cylinders = SUN_SSWAP16(sunlabel->ncyl); 118 g_sectors = SUN_SSWAP16(sunlabel->nsect); 119 } 120 update_units(); 121 current_label_type = LABEL_SUN; 122 g_partitions = 8; 123 return 1; 124} 125 126static const struct sun_predefined_drives { 127 const char *vendor; 128 const char *model; 129 unsigned short sparecyl; 130 unsigned short ncyl; 131 unsigned short nacyl; 132 unsigned short pcylcount; 133 unsigned short ntrks; 134 unsigned short nsect; 135 unsigned short rspeed; 136} sun_drives[] = { 137 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662}, 138 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662}, 139 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600}, 140 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400}, 141 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400}, 142 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200}, 143 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228}, 144 { "","SUN0104",1,974,2,1019,6,35,3662}, 145 { "","SUN0207",4,1254,2,1272,9,36,3600}, 146 { "","SUN0327",3,1545,2,1549,9,46,3600}, 147 { "","SUN0340",0,1538,2,1544,6,72,4200}, 148 { "","SUN0424",2,1151,2,2500,9,80,4400}, 149 { "","SUN0535",0,1866,2,2500,7,80,5400}, 150 { "","SUN0669",5,1614,2,1632,15,54,3600}, 151 { "","SUN1.0G",5,1703,2,1931,15,80,3597}, 152 { "","SUN1.05",0,2036,2,2038,14,72,5400}, 153 { "","SUN1.3G",6,1965,2,3500,17,80,5400}, 154 { "","SUN2.1G",0,2733,2,3500,19,80,5400}, 155 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394}, 156}; 157 158static const struct sun_predefined_drives * 159sun_autoconfigure_scsi(void) 160{ 161 const struct sun_predefined_drives *p = NULL; 162 163#ifdef SCSI_IOCTL_GET_IDLUN 164 unsigned int id[2]; 165 char buffer[2048]; 166 char buffer2[2048]; 167 FILE *pfd; 168 char *vendor; 169 char *model; 170 char *q; 171 int i; 172 173 if (ioctl(dev_fd, SCSI_IOCTL_GET_IDLUN, &id)) 174 return NULL; 175 176 sprintf(buffer, 177 "Host: scsi%u Channel: %02u Id: %02u Lun: %02u\n", 178 /* This is very wrong (works only if you have one HBA), 179 but I haven't found a way how to get hostno 180 from the current kernel */ 181 0, 182 (id[0]>>16) & 0xff, 183 id[0] & 0xff, 184 (id[0]>>8) & 0xff 185 ); 186 pfd = fopen_for_read("/proc/scsi/scsi"); 187 if (!pfd) { 188 return NULL; 189 } 190 while (fgets(buffer2, 2048, pfd)) { 191 if (strcmp(buffer, buffer2)) 192 continue; 193 if (!fgets(buffer2, 2048, pfd)) 194 break; 195 q = strstr(buffer2, "Vendor: "); 196 if (!q) 197 break; 198 q += 8; 199 vendor = q; 200 q = strstr(q, " "); 201 *q++ = '\0'; /* truncate vendor name */ 202 q = strstr(q, "Model: "); 203 if (!q) 204 break; 205 *q = '\0'; 206 q += 7; 207 model = q; 208 q = strstr(q, " Rev: "); 209 if (!q) 210 break; 211 *q = '\0'; 212 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) { 213 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor)) 214 continue; 215 if (!strstr(model, sun_drives[i].model)) 216 continue; 217 printf("Autoconfigure found a %s%s%s\n", 218 sun_drives[i].vendor, 219 (*sun_drives[i].vendor) ? " " : "", 220 sun_drives[i].model); 221 p = sun_drives + i; 222 break; 223 } 224 break; 225 } 226 fclose(pfd); 227#endif 228 return p; 229} 230 231static void 232create_sunlabel(void) 233{ 234 struct hd_geometry geometry; 235 unsigned ndiv; 236 unsigned char c; 237 const struct sun_predefined_drives *p = NULL; 238 239 printf(msg_building_new_label, "sun disklabel"); 240 241 sun_other_endian = BB_LITTLE_ENDIAN; 242 memset(MBRbuffer, 0, sizeof(MBRbuffer)); 243 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC); 244 if (!floppy) { 245 unsigned i; 246 puts("Drive type\n" 247 " ? auto configure\n" 248 " 0 custom (with hardware detected defaults)"); 249 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) { 250 printf(" %c %s%s%s\n", 251 i + 'a', sun_drives[i].vendor, 252 (*sun_drives[i].vendor) ? " " : "", 253 sun_drives[i].model); 254 } 255 while (1) { 256 c = read_nonempty("Select type (? for auto, 0 for custom): "); 257 if (c == '0') { 258 break; 259 } 260 if (c >= 'a' && c < 'a' + ARRAY_SIZE(sun_drives)) { 261 p = sun_drives + c - 'a'; 262 break; 263 } 264 if (c >= 'A' && c < 'A' + ARRAY_SIZE(sun_drives)) { 265 p = sun_drives + c - 'A'; 266 break; 267 } 268 if (c == '?' && scsi_disk) { 269 p = sun_autoconfigure_scsi(); 270 if (p) 271 break; 272 printf("Autoconfigure failed\n"); 273 } 274 } 275 } 276 if (!p || floppy) { 277 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) { 278 g_heads = geometry.heads; 279 g_sectors = geometry.sectors; 280 g_cylinders = geometry.cylinders; 281 } else { 282 g_heads = 0; 283 g_sectors = 0; 284 g_cylinders = 0; 285 } 286 if (floppy) { 287 sunlabel->nacyl = 0; 288 sunlabel->pcylcount = SUN_SSWAP16(g_cylinders); 289 sunlabel->rspeed = SUN_SSWAP16(300); 290 sunlabel->ilfact = SUN_SSWAP16(1); 291 sunlabel->sparecyl = 0; 292 } else { 293 g_heads = read_int(1, g_heads, 1024, 0, "Heads"); 294 g_sectors = read_int(1, g_sectors, 1024, 0, "Sectors/track"); 295 if (g_cylinders) 296 g_cylinders = read_int(1, g_cylinders - 2, 65535, 0, "Cylinders"); 297 else 298 g_cylinders = read_int(1, 0, 65535, 0, "Cylinders"); 299 sunlabel->nacyl = SUN_SSWAP16(read_int(0, 2, 65535, 0, "Alternate cylinders")); 300 sunlabel->pcylcount = SUN_SSWAP16(read_int(0, g_cylinders + SUN_SSWAP16(sunlabel->nacyl), 65535, 0, "Physical cylinders")); 301 sunlabel->rspeed = SUN_SSWAP16(read_int(1, 5400, 100000, 0, "Rotation speed (rpm)")); 302 sunlabel->ilfact = SUN_SSWAP16(read_int(1, 1, 32, 0, "Interleave factor")); 303 sunlabel->sparecyl = SUN_SSWAP16(read_int(0, 0, g_sectors, 0, "Extra sectors per cylinder")); 304 } 305 } else { 306 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl); 307 sunlabel->ncyl = SUN_SSWAP16(p->ncyl); 308 sunlabel->nacyl = SUN_SSWAP16(p->nacyl); 309 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount); 310 sunlabel->ntrks = SUN_SSWAP16(p->ntrks); 311 sunlabel->nsect = SUN_SSWAP16(p->nsect); 312 sunlabel->rspeed = SUN_SSWAP16(p->rspeed); 313 sunlabel->ilfact = SUN_SSWAP16(1); 314 g_cylinders = p->ncyl; 315 g_heads = p->ntrks; 316 g_sectors = p->nsect; 317 puts("You may change all the disk params from the x menu"); 318 } 319 320 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info), 321 "%s%s%s cyl %u alt %u hd %u sec %u", 322 p ? p->vendor : "", (p && *p->vendor) ? " " : "", 323 p ? p->model : (floppy ? "3,5\" floppy" : "Linux custom"), 324 g_cylinders, SUN_SSWAP16(sunlabel->nacyl), g_heads, g_sectors); 325 326 sunlabel->ntrks = SUN_SSWAP16(g_heads); 327 sunlabel->nsect = SUN_SSWAP16(g_sectors); 328 sunlabel->ncyl = SUN_SSWAP16(g_cylinders); 329 if (floppy) 330 set_sun_partition(0, 0, g_cylinders * g_heads * g_sectors, LINUX_NATIVE); 331 else { 332 if (g_cylinders * g_heads * g_sectors >= 150 * 2048) { 333 ndiv = g_cylinders - (50 * 2048 / (g_heads * g_sectors)); /* 50M swap */ 334 } else 335 ndiv = g_cylinders * 2 / 3; 336 set_sun_partition(0, 0, ndiv * g_heads * g_sectors, LINUX_NATIVE); 337 set_sun_partition(1, ndiv * g_heads * g_sectors, g_cylinders * g_heads * g_sectors, LINUX_SWAP); 338 sunlabel->infos[1].flags |= 0x01; /* Not mountable */ 339 } 340 set_sun_partition(2, 0, g_cylinders * g_heads * g_sectors, SUN_WHOLE_DISK); 341 { 342 unsigned short *ush = (unsigned short *)sunlabel; 343 unsigned short csum = 0; 344 while (ush < (unsigned short *)(&sunlabel->csum)) 345 csum ^= *ush++; 346 sunlabel->csum = csum; 347 } 348 349 set_all_unchanged(); 350 set_changed(0); 351 get_boot(CREATE_EMPTY_SUN); 352} 353 354static void 355toggle_sunflags(int i, unsigned char mask) 356{ 357 if (sunlabel->infos[i].flags & mask) 358 sunlabel->infos[i].flags &= ~mask; 359 else 360 sunlabel->infos[i].flags |= mask; 361 set_changed(i); 362} 363 364static void 365fetch_sun(unsigned *starts, unsigned *lens, unsigned *start, unsigned *stop) 366{ 367 int i, continuous = 1; 368 369 *start = 0; 370 *stop = g_cylinders * g_heads * g_sectors; 371 for (i = 0; i < g_partitions; i++) { 372 if (sunlabel->partitions[i].num_sectors 373 && sunlabel->infos[i].id 374 && sunlabel->infos[i].id != SUN_WHOLE_DISK) { 375 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors; 376 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors); 377 if (continuous) { 378 if (starts[i] == *start) 379 *start += lens[i]; 380 else if (starts[i] + lens[i] >= *stop) 381 *stop = starts[i]; 382 else 383 continuous = 0; 384 /* There will be probably more gaps 385 than one, so lets check afterwards */ 386 } 387 } else { 388 starts[i] = 0; 389 lens[i] = 0; 390 } 391 } 392} 393 394static unsigned *verify_sun_starts; 395 396static int 397verify_sun_cmp(int *a, int *b) 398{ 399 if (*a == -1) return 1; 400 if (*b == -1) return -1; 401 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1; 402 return -1; 403} 404 405static void 406verify_sun(void) 407{ 408 unsigned starts[8], lens[8], start, stop; 409 int i,j,k,starto,endo; 410 int array[8]; 411 412 verify_sun_starts = starts; 413 fetch_sun(starts, lens, &start, &stop); 414 for (k = 0; k < 7; k++) { 415 for (i = 0; i < 8; i++) { 416 if (k && (lens[i] % (g_heads * g_sectors))) { 417 printf("Partition %u doesn't end on cylinder boundary\n", i+1); 418 } 419 if (lens[i]) { 420 for (j = 0; j < i; j++) 421 if (lens[j]) { 422 if (starts[j] == starts[i]+lens[i]) { 423 starts[j] = starts[i]; lens[j] += lens[i]; 424 lens[i] = 0; 425 } else if (starts[i] == starts[j]+lens[j]){ 426 lens[j] += lens[i]; 427 lens[i] = 0; 428 } else if (!k) { 429 if (starts[i] < starts[j]+lens[j] 430 && starts[j] < starts[i]+lens[i]) { 431 starto = starts[i]; 432 if (starts[j] > starto) 433 starto = starts[j]; 434 endo = starts[i]+lens[i]; 435 if (starts[j]+lens[j] < endo) 436 endo = starts[j]+lens[j]; 437 printf("Partition %u overlaps with others in " 438 "sectors %u-%u\n", i+1, starto, endo); 439 } 440 } 441 } 442 } 443 } 444 } 445 for (i = 0; i < 8; i++) { 446 if (lens[i]) 447 array[i] = i; 448 else 449 array[i] = -1; 450 } 451 qsort(array, ARRAY_SIZE(array), sizeof(array[0]), 452 (int (*)(const void *,const void *)) verify_sun_cmp); 453 if (array[0] == -1) { 454 printf("No partitions defined\n"); 455 return; 456 } 457 stop = g_cylinders * g_heads * g_sectors; 458 if (starts[array[0]]) 459 printf("Unused gap - sectors %u-%u\n", 0, starts[array[0]]); 460 for (i = 0; i < 7 && array[i+1] != -1; i++) { 461 printf("Unused gap - sectors %u-%u\n", starts[array[i]]+lens[array[i]], starts[array[i+1]]); 462 } 463 start = starts[array[i]] + lens[array[i]]; 464 if (start < stop) 465 printf("Unused gap - sectors %u-%u\n", start, stop); 466} 467 468static void 469add_sun_partition(int n, int sys) 470{ 471 unsigned start, stop, stop2; 472 unsigned starts[8], lens[8]; 473 int whole_disk = 0; 474 475 char mesg[256]; 476 int i, first, last; 477 478 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) { 479 printf(msg_part_already_defined, n + 1); 480 return; 481 } 482 483 fetch_sun(starts, lens, &start, &stop); 484 if (stop <= start) { 485 if (n == 2) 486 whole_disk = 1; 487 else { 488 printf("Other partitions already cover the whole disk.\n" 489 "Delete/shrink them before retry.\n"); 490 return; 491 } 492 } 493 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR)); 494 while (1) { 495 if (whole_disk) 496 first = read_int(0, 0, 0, 0, mesg); 497 else 498 first = read_int(scround(start), scround(stop)+1, 499 scround(stop), 0, mesg); 500 if (display_in_cyl_units) 501 first *= units_per_sector; 502 else 503 /* Starting sector has to be properly aligned */ 504 first = (first + g_heads * g_sectors - 1) / (g_heads * g_sectors); 505 if (n == 2 && first != 0) 506 printf("\ 507It is highly recommended that the third partition covers the whole disk\n\ 508and is of type 'Whole disk'\n"); 509 /* ewt asks to add: "don't start a partition at cyl 0" 510 However, edmundo@rano.demon.co.uk writes: 511 "In addition to having a Sun partition table, to be able to 512 boot from the disc, the first partition, /dev/sdX1, must 513 start at cylinder 0. This means that /dev/sdX1 contains 514 the partition table and the boot block, as these are the 515 first two sectors of the disc. Therefore you must be 516 careful what you use /dev/sdX1 for. In particular, you must 517 not use a partition starting at cylinder 0 for Linux swap, 518 as that would overwrite the partition table and the boot 519 block. You may, however, use such a partition for a UFS 520 or EXT2 file system, as these file systems leave the first 521 1024 bytes undisturbed. */ 522 /* On the other hand, one should not use partitions 523 starting at block 0 in an md, or the label will 524 be trashed. */ 525 for (i = 0; i < g_partitions; i++) 526 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first) 527 break; 528 if (i < g_partitions && !whole_disk) { 529 if (n == 2 && !first) { 530 whole_disk = 1; 531 break; 532 } 533 printf("Sector %u is already allocated\n", first); 534 } else 535 break; 536 } 537 stop = g_cylinders * g_heads * g_sectors; 538 stop2 = stop; 539 for (i = 0; i < g_partitions; i++) { 540 if (starts[i] > first && starts[i] < stop) 541 stop = starts[i]; 542 } 543 snprintf(mesg, sizeof(mesg), 544 "Last %s or +size or +sizeM or +sizeK", 545 str_units(SINGULAR)); 546 if (whole_disk) 547 last = read_int(scround(stop2), scround(stop2), scround(stop2), 548 0, mesg); 549 else if (n == 2 && !first) 550 last = read_int(scround(first), scround(stop2), scround(stop2), 551 scround(first), mesg); 552 else 553 last = read_int(scround(first), scround(stop), scround(stop), 554 scround(first), mesg); 555 if (display_in_cyl_units) 556 last *= units_per_sector; 557 if (n == 2 && !first) { 558 if (last >= stop2) { 559 whole_disk = 1; 560 last = stop2; 561 } else if (last > stop) { 562 printf( 563"You haven't covered the whole disk with the 3rd partition,\n" 564"but your value %u %s covers some other partition.\n" 565"Your entry has been changed to %u %s\n", 566 scround(last), str_units(SINGULAR), 567 scround(stop), str_units(SINGULAR)); 568 last = stop; 569 } 570 } else if (!whole_disk && last > stop) 571 last = stop; 572 573 if (whole_disk) 574 sys = SUN_WHOLE_DISK; 575 set_sun_partition(n, first, last, sys); 576} 577 578static void 579sun_delete_partition(int i) 580{ 581 unsigned int nsec; 582 583 if (i == 2 584 && sunlabel->infos[i].id == SUN_WHOLE_DISK 585 && !sunlabel->partitions[i].start_cylinder 586 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == g_heads * g_sectors * g_cylinders) 587 printf("If you want to maintain SunOS/Solaris compatibility, " 588 "consider leaving this\n" 589 "partition as Whole disk (5), starting at 0, with %u " 590 "sectors\n", nsec); 591 sunlabel->infos[i].id = 0; 592 sunlabel->partitions[i].num_sectors = 0; 593} 594 595static void 596sun_change_sysid(int i, int sys) 597{ 598 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) { 599 read_maybe_empty( 600 "It is highly recommended that the partition at offset 0\n" 601 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n" 602 "there may destroy your partition table and bootblock.\n" 603 "Type YES if you're very sure you would like that partition\n" 604 "tagged with 82 (Linux swap): "); 605 if (strcmp (line_ptr, "YES\n")) 606 return; 607 } 608 switch (sys) { 609 case SUNOS_SWAP: 610 case LINUX_SWAP: 611 /* swaps are not mountable by default */ 612 sunlabel->infos[i].flags |= 0x01; 613 break; 614 default: 615 /* assume other types are mountable; 616 user can change it anyway */ 617 sunlabel->infos[i].flags &= ~0x01; 618 break; 619 } 620 sunlabel->infos[i].id = sys; 621} 622 623static void 624sun_list_table(int xtra) 625{ 626 int i, w; 627 628 w = strlen(disk_device); 629 if (xtra) 630 printf( 631 "\nDisk %s (Sun disk label): %u heads, %u sectors, %u rpm\n" 632 "%u cylinders, %u alternate cylinders, %u physical cylinders\n" 633 "%u extra sects/cyl, interleave %u:1\n" 634 "%s\n" 635 "Units = %s of %u * 512 bytes\n\n", 636 disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed), 637 g_cylinders, SUN_SSWAP16(sunlabel->nacyl), 638 SUN_SSWAP16(sunlabel->pcylcount), 639 SUN_SSWAP16(sunlabel->sparecyl), 640 SUN_SSWAP16(sunlabel->ilfact), 641 (char *)sunlabel, 642 str_units(PLURAL), units_per_sector); 643 else 644 printf( 645 "\nDisk %s (Sun disk label): %u heads, %u sectors, %u cylinders\n" 646 "Units = %s of %u * 512 bytes\n\n", 647 disk_device, g_heads, g_sectors, g_cylinders, 648 str_units(PLURAL), units_per_sector); 649 650 printf("%*s Flag Start End Blocks Id System\n", 651 w + 1, "Device"); 652 for (i = 0; i < g_partitions; i++) { 653 if (sunlabel->partitions[i].num_sectors) { 654 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors; 655 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors); 656 printf("%s %c%c %9lu %9lu %9lu%c %2x %s\n", 657 partname(disk_device, i+1, w), /* device */ 658 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */ 659 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ', 660 (long) scround(start), /* start */ 661 (long) scround(start+len), /* end */ 662 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */ 663 sunlabel->infos[i].id, /* type id */ 664 partition_type(sunlabel->infos[i].id)); /* type name */ 665 } 666 } 667} 668 669#if ENABLE_FEATURE_FDISK_ADVANCED 670 671static void 672sun_set_alt_cyl(void) 673{ 674 sunlabel->nacyl = 675 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->nacyl), 65535, 0, 676 "Number of alternate cylinders")); 677} 678 679static void 680sun_set_ncyl(int cyl) 681{ 682 sunlabel->ncyl = SUN_SSWAP16(cyl); 683} 684 685static void 686sun_set_xcyl(void) 687{ 688 sunlabel->sparecyl = 689 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), g_sectors, 0, 690 "Extra sectors per cylinder")); 691} 692 693static void 694sun_set_ilfact(void) 695{ 696 sunlabel->ilfact = 697 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0, 698 "Interleave factor")); 699} 700 701static void 702sun_set_rspeed(void) 703{ 704 sunlabel->rspeed = 705 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0, 706 "Rotation speed (rpm)")); 707} 708 709static void 710sun_set_pcylcount(void) 711{ 712 sunlabel->pcylcount = 713 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0, 714 "Number of physical cylinders")); 715} 716#endif /* FEATURE_FDISK_ADVANCED */ 717 718static void 719sun_write_table(void) 720{ 721 unsigned short *ush = (unsigned short *)sunlabel; 722 unsigned short csum = 0; 723 724 while (ush < (unsigned short *)(&sunlabel->csum)) 725 csum ^= *ush++; 726 sunlabel->csum = csum; 727 write_sector(0, sunlabel); 728} 729#endif /* SUN_LABEL */ 730