1 #if ENABLE_FEATURE_SUN_LABEL
3 #define SUN_LABEL_MAGIC 0xDABE
4 #define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
5 #define SUN_SSWAP16(x) (sun_other_endian ? fdisk_swap16(x) : (uint16_t)(x))
6 #define SUN_SSWAP32(x) (sun_other_endian ? fdisk_swap32(x) : (uint32_t)(x))
8 /* Copied from linux/major.h */
11 #define SCSI_IOCTL_GET_IDLUN 0x5382
16 * I think this is mostly, or entirely, due to
17 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
19 * Merged with fdisk for other architectures, aeb, June 1998.
21 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
22 * Internationalization
26 static int sun_other_endian;
38 guess_device_type(void)
42 if (fstat(fd, &bootstat) < 0) {
45 } else if (S_ISBLK(bootstat.st_mode)
46 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
47 major(bootstat.st_rdev) == IDE1_MAJOR)) {
50 } else if (S_ISBLK(bootstat.st_mode)
51 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
60 static const struct systypes sun_sys_types[] = {
61 { "\x00" "Empty" }, /* 0 */
62 { "\x01" "Boot" }, /* 1 */
63 { "\x02" "SunOS root" }, /* 2 */
64 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
65 { "\x04" "SunOS usr" }, /* 4 */
66 { "\x05" "Whole disk" }, /* SUN_WHOLE_DISK */
67 { "\x06" "SunOS stand" }, /* 6 */
68 { "\x07" "SunOS var" }, /* 7 */
69 { "\x08" "SunOS home" }, /* 8 */
70 { "\x82" "Linux swap" }, /* LINUX_SWAP */
71 { "\x83" "Linux native" }, /* LINUX_NATIVE */
72 { "\x8e" "Linux LVM" }, /* 0x8e */
73 /* New (2.2.x) raid partition with autodetect using persistent superblock */
74 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
80 set_sun_partition(int i, uint start, uint stop, int sysid)
82 sunlabel->infos[i].id = sysid;
83 sunlabel->partitions[i].start_cylinder =
84 SUN_SSWAP32(start / (heads * sectors));
85 sunlabel->partitions[i].num_sectors =
86 SUN_SSWAP32(stop - start);
96 if (sunlabel->magic != SUN_LABEL_MAGIC
97 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
98 current_label_type = label_dos;
102 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
103 ush = ((unsigned short *) (sunlabel + 1)) - 1;
104 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
106 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
107 "Probably you'll have to set all the values,\n"
108 "e.g. heads, sectors, cylinders and partitions\n"
109 "or force a fresh label (s command in main menu)\n"));
111 heads = SUN_SSWAP16(sunlabel->ntrks);
112 cylinders = SUN_SSWAP16(sunlabel->ncyl);
113 sectors = SUN_SSWAP16(sunlabel->nsect);
116 current_label_type = label_sun;
121 static const struct sun_predefined_drives {
124 unsigned short sparecyl;
126 unsigned short nacyl;
127 unsigned short pcylcount;
128 unsigned short ntrks;
129 unsigned short nsect;
130 unsigned short rspeed;
132 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
133 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
134 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
135 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
136 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
137 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
138 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
139 { "","SUN0104",1,974,2,1019,6,35,3662},
140 { "","SUN0207",4,1254,2,1272,9,36,3600},
141 { "","SUN0327",3,1545,2,1549,9,46,3600},
142 { "","SUN0340",0,1538,2,1544,6,72,4200},
143 { "","SUN0424",2,1151,2,2500,9,80,4400},
144 { "","SUN0535",0,1866,2,2500,7,80,5400},
145 { "","SUN0669",5,1614,2,1632,15,54,3600},
146 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
147 { "","SUN1.05",0,2036,2,2038,14,72,5400},
148 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
149 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
150 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
153 static const struct sun_predefined_drives *
154 sun_autoconfigure_scsi(void)
156 const struct sun_predefined_drives *p = NULL;
158 #ifdef SCSI_IOCTL_GET_IDLUN
168 if (ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id))
172 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
173 /* This is very wrong (works only if you have one HBA),
174 but I haven't found a way how to get hostno
175 from the current kernel */
181 pfd = fopen("/proc/scsi/scsi", "r");
185 while (fgets(buffer2, 2048, pfd)) {
186 if (strcmp(buffer, buffer2))
188 if (!fgets(buffer2, 2048, pfd))
190 q = strstr(buffer2, "Vendor: ");
196 *q++ = '\0'; /* truncate vendor name */
197 q = strstr(q, "Model: ");
203 q = strstr(q, " Rev: ");
207 for (i = 0; i < SIZE(sun_drives); i++) {
208 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
210 if (!strstr(model, sun_drives[i].model))
212 printf(_("Autoconfigure found a %s%s%s\n"),
213 sun_drives[i].vendor,
214 (*sun_drives[i].vendor) ? " " : "",
215 sun_drives[i].model);
227 create_sunlabel(void)
229 struct hd_geometry geometry;
233 const struct sun_predefined_drives *p = NULL;
236 _("Building a new sun disklabel. Changes will remain in memory only,\n"
237 "until you decide to write them. After that, of course, the previous\n"
238 "content won't be recoverable.\n\n"));
239 sun_other_endian = BB_LITTLE_ENDIAN;
240 memset(MBRbuffer, 0, sizeof(MBRbuffer));
241 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
243 puts(_("Drive type\n"
244 " ? auto configure\n"
245 " 0 custom (with hardware detected defaults)"));
246 for (i = 0; i < SIZE(sun_drives); i++) {
247 printf(" %c %s%s%s\n",
248 i + 'a', sun_drives[i].vendor,
249 (*sun_drives[i].vendor) ? " " : "",
250 sun_drives[i].model);
253 c = read_nonempty(_("Select type (? for auto, 0 for custom): "));
254 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
255 p = sun_drives + c - 'a';
257 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
258 p = sun_drives + c - 'A';
260 } else if (c == '0') {
262 } else if (c == '?' && scsi_disk) {
263 p = sun_autoconfigure_scsi();
265 printf(_("Autoconfigure failed.\n"));
272 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
273 heads = geometry.heads;
274 sectors = geometry.sectors;
275 cylinders = geometry.cylinders;
283 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
284 sunlabel->rspeed = SUN_SSWAP16(300);
285 sunlabel->ilfact = SUN_SSWAP16(1);
286 sunlabel->sparecyl = 0;
288 heads = read_int(1,heads,1024,0,_("Heads"));
289 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
291 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
293 cylinders = read_int(1,0,65535,0,_("Cylinders"));
294 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
295 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
296 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
297 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
298 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
301 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
302 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
303 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
304 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
305 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
306 sunlabel->nsect = SUN_SSWAP16(p->nsect);
307 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
308 sunlabel->ilfact = SUN_SSWAP16(1);
312 puts(_("You may change all the disk params from the x menu"));
315 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
316 "%s%s%s cyl %d alt %d hd %d sec %d",
317 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
318 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
319 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
321 sunlabel->ntrks = SUN_SSWAP16(heads);
322 sunlabel->nsect = SUN_SSWAP16(sectors);
323 sunlabel->ncyl = SUN_SSWAP16(cylinders);
325 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
327 if (cylinders * heads * sectors >= 150 * 2048) {
328 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
330 ndiv = cylinders * 2 / 3;
331 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
332 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
333 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
335 set_sun_partition(2, 0, cylinders * heads * sectors, SUN_WHOLE_DISK);
337 unsigned short *ush = (unsigned short *)sunlabel;
338 unsigned short csum = 0;
339 while (ush < (unsigned short *)(&sunlabel->csum))
341 sunlabel->csum = csum;
346 get_boot(create_empty_sun);
350 toggle_sunflags(int i, unsigned char mask)
352 if (sunlabel->infos[i].flags & mask)
353 sunlabel->infos[i].flags &= ~mask;
355 sunlabel->infos[i].flags |= mask;
360 fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
362 int i, continuous = 1;
365 *stop = cylinders * heads * sectors;
366 for (i = 0; i < partitions; i++) {
367 if (sunlabel->partitions[i].num_sectors
368 && sunlabel->infos[i].id
369 && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
370 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
371 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
373 if (starts[i] == *start)
375 else if (starts[i] + lens[i] >= *stop)
379 /* There will be probably more gaps
380 than one, so lets check afterwards */
389 static uint *verify_sun_starts;
392 verify_sun_cmp(int *a, int *b)
394 if (*a == -1) return 1;
395 if (*b == -1) return -1;
396 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
403 uint starts[8], lens[8], start, stop;
404 int i,j,k,starto,endo;
407 verify_sun_starts = starts;
408 fetch_sun(starts,lens,&start,&stop);
409 for (k = 0; k < 7; k++) {
410 for (i = 0; i < 8; i++) {
411 if (k && (lens[i] % (heads * sectors))) {
412 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
415 for (j = 0; j < i; j++)
417 if (starts[j] == starts[i]+lens[i]) {
418 starts[j] = starts[i]; lens[j] += lens[i];
420 } else if (starts[i] == starts[j]+lens[j]){
424 if (starts[i] < starts[j]+lens[j]
425 && starts[j] < starts[i]+lens[i]) {
427 if (starts[j] > starto)
429 endo = starts[i]+lens[i];
430 if (starts[j]+lens[j] < endo)
431 endo = starts[j]+lens[j];
432 printf(_("Partition %d overlaps with others in "
433 "sectors %d-%d\n"), i+1, starto, endo);
440 for (i = 0; i < 8; i++) {
446 qsort(array,SIZE(array),sizeof(array[0]),
447 (int (*)(const void *,const void *)) verify_sun_cmp);
448 if (array[0] == -1) {
449 printf(_("No partitions defined\n"));
452 stop = cylinders * heads * sectors;
453 if (starts[array[0]])
454 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
455 for (i = 0; i < 7 && array[i+1] != -1; i++) {
456 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
458 start = starts[array[i]] + lens[array[i]];
460 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
464 add_sun_partition(int n, int sys)
466 uint start, stop, stop2;
467 uint starts[8], lens[8];
473 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
474 printf(_("Partition %d is already defined. Delete "
475 "it before re-adding it.\n"), n + 1);
479 fetch_sun(starts,lens,&start,&stop);
484 printf(_("Other partitions already cover the whole disk.\nDelete "
485 "some/shrink them before retry.\n"));
489 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
492 first = read_int(0, 0, 0, 0, mesg);
494 first = read_int(scround(start), scround(stop)+1,
495 scround(stop), 0, mesg);
496 if (display_in_cyl_units)
497 first *= units_per_sector;
499 /* Starting sector has to be properly aligned */
500 first = (first + heads * sectors - 1) / (heads * sectors);
501 if (n == 2 && first != 0)
503 It is highly recommended that the third partition covers the whole disk\n\
504 and is of type `Whole disk'\n");
505 /* ewt asks to add: "don't start a partition at cyl 0"
506 However, edmundo@rano.demon.co.uk writes:
507 "In addition to having a Sun partition table, to be able to
508 boot from the disc, the first partition, /dev/sdX1, must
509 start at cylinder 0. This means that /dev/sdX1 contains
510 the partition table and the boot block, as these are the
511 first two sectors of the disc. Therefore you must be
512 careful what you use /dev/sdX1 for. In particular, you must
513 not use a partition starting at cylinder 0 for Linux swap,
514 as that would overwrite the partition table and the boot
515 block. You may, however, use such a partition for a UFS
516 or EXT2 file system, as these file systems leave the first
517 1024 bytes undisturbed. */
518 /* On the other hand, one should not use partitions
519 starting at block 0 in an md, or the label will
521 for (i = 0; i < partitions; i++)
522 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
524 if (i < partitions && !whole_disk) {
525 if (n == 2 && !first) {
529 printf(_("Sector %d is already allocated\n"), first);
533 stop = cylinders * heads * sectors;
535 for (i = 0; i < partitions; i++) {
536 if (starts[i] > first && starts[i] < stop)
539 snprintf(mesg, sizeof(mesg),
540 _("Last %s or +size or +sizeM or +sizeK"),
541 str_units(SINGULAR));
543 last = read_int(scround(stop2), scround(stop2), scround(stop2),
545 else if (n == 2 && !first)
546 last = read_int(scround(first), scround(stop2), scround(stop2),
547 scround(first), mesg);
549 last = read_int(scround(first), scround(stop), scround(stop),
550 scround(first), mesg);
551 if (display_in_cyl_units)
552 last *= units_per_sector;
553 if (n == 2 && !first) {
557 } else if (last > stop) {
558 printf(_("You haven't covered the whole disk with "
559 "the 3rd partition, but your value\n"
560 "%d %s covers some other partition. "
561 "Your entry has been changed\n"
563 scround(last), str_units(SINGULAR),
564 scround(stop), str_units(SINGULAR));
567 } else if (!whole_disk && last > stop)
571 sys = SUN_WHOLE_DISK;
572 set_sun_partition(n, first, last, sys);
576 sun_delete_partition(int i)
581 && sunlabel->infos[i].id == SUN_WHOLE_DISK
582 && !sunlabel->partitions[i].start_cylinder
583 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
584 printf(_("If you want to maintain SunOS/Solaris compatibility, "
585 "consider leaving this\n"
586 "partition as Whole disk (5), starting at 0, with %u "
588 sunlabel->infos[i].id = 0;
589 sunlabel->partitions[i].num_sectors = 0;
593 sun_change_sysid(int i, int sys)
595 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
597 _("It is highly recommended that the partition at offset 0\n"
598 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
599 "there may destroy your partition table and bootblock.\n"
600 "Type YES if you're very sure you would like that partition\n"
601 "tagged with 82 (Linux swap): "));
602 if (strcmp (line_ptr, _("YES\n")))
608 /* swaps are not mountable by default */
609 sunlabel->infos[i].flags |= 0x01;
612 /* assume other types are mountable;
613 user can change it anyway */
614 sunlabel->infos[i].flags &= ~0x01;
617 sunlabel->infos[i].id = sys;
621 sun_list_table(int xtra)
625 w = strlen(disk_device);
628 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
629 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
630 "%d extra sects/cyl, interleave %d:1\n"
632 "Units = %s of %d * 512 bytes\n\n"),
633 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
634 cylinders, SUN_SSWAP16(sunlabel->nacyl),
635 SUN_SSWAP16(sunlabel->pcylcount),
636 SUN_SSWAP16(sunlabel->sparecyl),
637 SUN_SSWAP16(sunlabel->ilfact),
639 str_units(PLURAL), units_per_sector);
642 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
643 "Units = %s of %d * 512 bytes\n\n"),
644 disk_device, heads, sectors, cylinders,
645 str_units(PLURAL), units_per_sector);
647 printf(_("%*s Flag Start End Blocks Id System\n"),
649 for (i = 0 ; i < partitions; i++) {
650 if (sunlabel->partitions[i].num_sectors) {
651 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
652 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
653 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
654 partname(disk_device, i+1, w), /* device */
655 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
656 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
657 (long) scround(start), /* start */
658 (long) scround(start+len), /* end */
659 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
660 sunlabel->infos[i].id, /* type id */
661 partition_type(sunlabel->infos[i].id)); /* type name */
666 #if ENABLE_FEATURE_FDISK_ADVANCED
669 sun_set_alt_cyl(void)
672 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
673 _("Number of alternate cylinders")));
677 sun_set_ncyl(int cyl)
679 sunlabel->ncyl = SUN_SSWAP16(cyl);
686 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
687 _("Extra sectors per cylinder")));
694 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
695 _("Interleave factor")));
702 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
703 _("Rotation speed (rpm)")));
707 sun_set_pcylcount(void)
709 sunlabel->pcylcount =
710 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
711 _("Number of physical cylinders")));
713 #endif /* FEATURE_FDISK_ADVANCED */
716 sun_write_table(void)
718 unsigned short *ush = (unsigned short *)sunlabel;
719 unsigned short csum = 0;
721 while (ush < (unsigned short *)(&sunlabel->csum))
723 sunlabel->csum = csum;
724 if (lseek(fd, 0, SEEK_SET) < 0)
725 fdisk_fatal(unable_to_seek);
726 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
727 fdisk_fatal(unable_to_write);
729 #endif /* SUN_LABEL */