]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - fdisk/fdisksunlabel.c
4 * I think this is mostly, or entirely, due to
5 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
7 * Merged with fdisk for other architectures, aeb, June 1998.
9 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
10 * Internationalization
13 #include <stdio.h> /* stderr */
14 #include <stdlib.h> /* uint */
15 #include <string.h> /* strstr */
16 #include <unistd.h> /* write */
17 #include <sys/ioctl.h> /* ioctl */
18 #include <sys/stat.h> /* stat */
22 #include "../defines.h" /* for HAVE_scsi_h */
24 #define u_char unsigned char
25 #include <scsi/scsi.h> /* SCSI_IOCTL_GET_IDLUN */
28 #include <linux/major.h> /* FLOPPY_MAJOR */
29 #include <linux/hdreg.h> /* HDIO_GETGEO */
33 #include "fdisksunlabel.h"
35 static int other_endian
= 0;
36 static int scsi_disk
= 0;
37 static int floppy
= 0;
39 #define LINUX_SWAP 0x82
40 #define LINUX_NATIVE 0x83
42 struct systypes sun_sys_types
[] = {
45 {2, N_("SunOS root")},
46 {SUNOS_SWAP
, N_("SunOS swap")},
48 {WHOLE_DISK
, N_("Whole disk")},
49 {6, N_("SunOS stand")},
51 {8, N_("SunOS home")},
52 {LINUX_SWAP
, N_("Linux swap")},
53 {LINUX_NATIVE
, N_("Linux native")},
54 {0x8e, N_("Linux LVM")},
58 static inline unsigned short __swap16(unsigned short x
) {
59 return (((__u16
)(x
) & 0xFF) << 8) | (((__u16
)(x
) & 0xFF00) >> 8);
61 static inline __u32
__swap32(__u32 x
) {
62 return (((__u32
)(x
) & 0xFF) << 24) | (((__u32
)(x
) & 0xFF00) << 8) | (((__u32
)(x
) & 0xFF0000) >> 8) | (((__u32
)(x
) & 0xFF000000) >> 24);
66 get_num_sectors(struct sun_partition p
) {
67 return SSWAP32(p
.num_sectors
);
76 void guess_device_type(int fd
) {
79 if (fstat (fd
, &bootstat
) < 0) {
82 } else if (S_ISBLK(bootstat
.st_mode
)
83 && ((bootstat
.st_rdev
>> 8) == IDE0_MAJOR
||
84 (bootstat
.st_rdev
>> 8) == IDE1_MAJOR
)) {
87 } else if (S_ISBLK(bootstat
.st_mode
)
88 && (bootstat
.st_rdev
>> 8) == FLOPPY_MAJOR
) {
98 set_sun_partition(int i
, uint start
, uint stop
, int sysid
) {
99 sunlabel
->infos
[i
].id
= sysid
;
100 sunlabel
->partitions
[i
].start_cylinder
=
101 SSWAP32(start
/ (heads
* sectors
));
102 sunlabel
->partitions
[i
].num_sectors
=
103 SSWAP32(stop
- start
);
115 check_sun_label(void) {
119 if (sunlabel
->magic
!= SUN_LABEL_MAGIC
&&
120 sunlabel
->magic
!= SUN_LABEL_MAGIC_SWAPPED
) {
125 other_endian
= (sunlabel
->magic
== SUN_LABEL_MAGIC_SWAPPED
);
126 ush
= ((unsigned short *) (sunlabel
+ 1)) - 1;
127 for (csum
= 0; ush
>= (unsigned short *)sunlabel
;) csum
^= *ush
--;
129 fprintf(stderr
,_("Detected sun disklabel with wrong checksum.\n"
130 "Probably you'll have to set all the values,\n"
131 "e.g. heads, sectors, cylinders and partitions\n"
132 "or force a fresh label (s command in main menu)\n"));
134 heads
= SSWAP16(sunlabel
->ntrks
);
135 cylinders
= SSWAP16(sunlabel
->ncyl
);
136 sectors
= SSWAP16(sunlabel
->nsect
);
144 struct sun_predefined_drives
{
147 unsigned short sparecyl
;
149 unsigned short nacyl
;
150 unsigned short pcylcount
;
151 unsigned short ntrks
;
152 unsigned short nsect
;
153 unsigned short rspeed
;
155 {"Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
156 {"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
157 {"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
158 {"IBM","DPES-31080",0,4901,2,4903,4,108,5400},
159 {"IBM","DORS-32160",0,1015,2,1017,67,62,5400},
160 {"IBM","DNES-318350",0,11199,2,11474,10,320,7200},
161 {"SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
162 {"","SUN0104",1,974,2,1019,6,35,3662},
163 {"","SUN0207",4,1254,2,1272,9,36,3600},
164 {"","SUN0327",3,1545,2,1549,9,46,3600},
165 {"","SUN0340",0,1538,2,1544,6,72,4200},
166 {"","SUN0424",2,1151,2,2500,9,80,4400},
167 {"","SUN0535",0,1866,2,2500,7,80,5400},
168 {"","SUN0669",5,1614,2,1632,15,54,3600},
169 {"","SUN1.0G",5,1703,2,1931,15,80,3597},
170 {"","SUN1.05",0,2036,2,2038,14,72,5400},
171 {"","SUN1.3G",6,1965,2,3500,17,80,5400},
172 {"","SUN2.1G",0,2733,2,3500,19,80,5400},
173 {"IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
176 static struct sun_predefined_drives
*
177 sun_autoconfigure_scsi(void) {
178 struct sun_predefined_drives
*p
= NULL
;
180 #ifdef SCSI_IOCTL_GET_IDLUN
190 if (!ioctl(fd
, SCSI_IOCTL_GET_IDLUN
, &id
)) {
192 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
194 ((id
[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
196 /* This is very wrong (works only if you have one HBA),
197 but I haven't found a way how to get hostno
198 from the current kernel */
204 pfd
= fopen("/proc/scsi/scsi","r");
206 while (fgets(buffer2
,2048,pfd
)) {
207 if (!strcmp(buffer
, buffer2
)) {
208 if (fgets(buffer2
,2048,pfd
)) {
209 q
= strstr(buffer2
,"Vendor: ");
214 *q
++ = 0; /* truncate vendor name */
215 q
= strstr(q
,"Model: ");
220 q
= strstr(q
," Rev: ");
223 for (i
= 0; i
< SIZE(sun_drives
); i
++) {
224 if (*sun_drives
[i
].vendor
&& strcasecmp(sun_drives
[i
].vendor
, vendor
))
226 if (!strstr(model
, sun_drives
[i
].model
))
228 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives
[i
].vendor
,(*sun_drives
[i
].vendor
) ? " " : "",sun_drives
[i
].model
);
246 void create_sunlabel(void)
248 struct hd_geometry geometry
;
252 struct sun_predefined_drives
*p
= NULL
;
255 _("Building a new sun disklabel. Changes will remain in memory only,\n"
256 "until you decide to write them. After that, of course, the previous\n"
257 "content won't be recoverable.\n\n"));
258 #if BYTE_ORDER == LITTLE_ENDIAN
263 memset(MBRbuffer
, 0, sizeof(MBRbuffer
));
264 sunlabel
->magic
= SSWAP16(SUN_LABEL_MAGIC
);
266 puts(_("Drive type\n"
267 " ? auto configure\n"
268 " 0 custom (with hardware detected defaults)"));
269 for (i
= 0; i
< SIZE(sun_drives
); i
++) {
270 printf(" %c %s%s%s\n",
271 i
+ 'a', sun_drives
[i
].vendor
,
272 (*sun_drives
[i
].vendor
) ? " " : "",
273 sun_drives
[i
].model
);
276 c
= read_char(_("Select type (? for auto, 0 for custom): "));
277 if (c
>= 'a' && c
< 'a' + SIZE(sun_drives
)) {
278 p
= sun_drives
+ c
- 'a';
280 } else if (c
>= 'A' && c
< 'A' + SIZE(sun_drives
)) {
281 p
= sun_drives
+ c
- 'A';
283 } else if (c
== '0') {
285 } else if (c
== '?' && scsi_disk
) {
286 p
= sun_autoconfigure_scsi();
288 printf(_("Autoconfigure failed.\n"));
296 if (!ioctl(fd
, HDIO_REQ
, &geometry
)) {
298 if (!ioctl(fd
, HDIO_GETGEO
, &geometry
)) {
300 heads
= geometry
.heads
;
301 sectors
= geometry
.sectors
;
302 cylinders
= geometry
.cylinders
;
310 sunlabel
->pcylcount
= SSWAP16(cylinders
);
311 sunlabel
->rspeed
= SSWAP16(300);
312 sunlabel
->ilfact
= SSWAP16(1);
313 sunlabel
->sparecyl
= 0;
315 heads
= read_int(1,heads
,1024,0,_("Heads"));
316 sectors
= read_int(1,sectors
,1024,0,_("Sectors/track"));
318 cylinders
= read_int(1,cylinders
-2,65535,0,_("Cylinders"));
320 cylinders
= read_int(1,0,65535,0,_("Cylinders"));
322 SSWAP16(read_int(0,2,65535,0,
323 _("Alternate cylinders")));
324 sunlabel
->pcylcount
=
325 SSWAP16(read_int(0,cylinders
+SSWAP16(sunlabel
->nacyl
),
326 65535,0,_("Physical cylinders")));
328 SSWAP16(read_int(1,5400,100000,0,
329 _("Rotation speed (rpm)")));
331 SSWAP16(read_int(1,1,32,0,_("Interleave factor")));
333 SSWAP16(read_int(0,0,sectors
,0,
334 _("Extra sectors per cylinder")));
337 sunlabel
->sparecyl
= SSWAP16(p
->sparecyl
);
338 sunlabel
->ncyl
= SSWAP16(p
->ncyl
);
339 sunlabel
->nacyl
= SSWAP16(p
->nacyl
);
340 sunlabel
->pcylcount
= SSWAP16(p
->pcylcount
);
341 sunlabel
->ntrks
= SSWAP16(p
->ntrks
);
342 sunlabel
->nsect
= SSWAP16(p
->nsect
);
343 sunlabel
->rspeed
= SSWAP16(p
->rspeed
);
344 sunlabel
->ilfact
= SSWAP16(1);
348 puts(_("You may change all the disk params from the x menu"));
351 sprintf(sunlabel
->info
, "%s%s%s cyl %d alt %d hd %d sec %d",
353 (p
&& *p
->vendor
) ? " " : "",
354 p
? p
->model
: (floppy
? _("3,5\" floppy") : _("Linux custom")),
355 cylinders
, SSWAP16(sunlabel
->nacyl
), heads
, sectors
);
357 sunlabel
->ntrks
= SSWAP16(heads
);
358 sunlabel
->nsect
= SSWAP16(sectors
);
359 sunlabel
->ncyl
= SSWAP16(cylinders
);
361 set_sun_partition(0, 0, cylinders
* heads
* sectors
, LINUX_NATIVE
);
363 if (cylinders
* heads
* sectors
>= 150 * 2048) {
364 ndiv
= cylinders
- (50 * 2048 / (heads
* sectors
)); /* 50M swap */
366 ndiv
= cylinders
* 2 / 3;
367 set_sun_partition(0, 0, ndiv
* heads
* sectors
, LINUX_NATIVE
);
368 set_sun_partition(1, ndiv
* heads
* sectors
, cylinders
* heads
* sectors
, LINUX_SWAP
);
369 sunlabel
->infos
[1].flags
|= 0x01; /* Not mountable */
371 set_sun_partition(2, 0, cylinders
* heads
* sectors
, WHOLE_DISK
);
373 unsigned short *ush
= (unsigned short *)sunlabel
;
374 unsigned short csum
= 0;
375 while(ush
< (unsigned short *)(&sunlabel
->csum
))
377 sunlabel
->csum
= csum
;
382 get_boot(create_empty
);
386 toggle_sunflags(int i
, unsigned char mask
) {
387 if (sunlabel
->infos
[i
].flags
& mask
)
388 sunlabel
->infos
[i
].flags
&= ~mask
;
389 else sunlabel
->infos
[i
].flags
|= mask
;
394 fetch_sun(uint
*starts
, uint
*lens
, uint
*start
, uint
*stop
) {
395 int i
, continuous
= 1;
396 *start
= 0; *stop
= cylinders
* heads
* sectors
;
397 for (i
= 0; i
< partitions
; i
++) {
398 if (sunlabel
->partitions
[i
].num_sectors
399 && sunlabel
->infos
[i
].id
400 && sunlabel
->infos
[i
].id
!= WHOLE_DISK
) {
401 starts
[i
] = SSWAP32(sunlabel
->partitions
[i
].start_cylinder
) * heads
* sectors
;
402 lens
[i
] = SSWAP32(sunlabel
->partitions
[i
].num_sectors
);
404 if (starts
[i
] == *start
)
406 else if (starts
[i
] + lens
[i
] >= *stop
)
410 /* There will be probably more gaps
411 than one, so lets check afterwards */
420 static uint
*verify_sun_starts
;
423 verify_sun_cmp(int *a
, int *b
) {
424 if (*a
== -1) return 1;
425 if (*b
== -1) return -1;
426 if (verify_sun_starts
[*a
] > verify_sun_starts
[*b
]) return 1;
432 uint starts
[8], lens
[8], start
, stop
;
433 int i
,j
,k
,starto
,endo
;
436 verify_sun_starts
= starts
;
437 fetch_sun(starts
,lens
,&start
,&stop
);
438 for (k
= 0; k
< 7; k
++) {
439 for (i
= 0; i
< 8; i
++) {
440 if (k
&& (lens
[i
] % (heads
* sectors
))) {
441 printf(_("Partition %d doesn't end on cylinder boundary\n"), i
+1);
444 for (j
= 0; j
< i
; j
++)
446 if (starts
[j
] == starts
[i
]+lens
[i
]) {
447 starts
[j
] = starts
[i
]; lens
[j
] += lens
[i
];
449 } else if (starts
[i
] == starts
[j
]+lens
[j
]){
453 if (starts
[i
] < starts
[j
]+lens
[j
] &&
454 starts
[j
] < starts
[i
]+lens
[i
]) {
456 if (starts
[j
] > starto
)
458 endo
= starts
[i
]+lens
[i
];
459 if (starts
[j
]+lens
[j
] < endo
)
460 endo
= starts
[j
]+lens
[j
];
461 printf(_("Partition %d overlaps with others in "
462 "sectors %d-%d\n"), i
+1, starto
, endo
);
469 for (i
= 0; i
< 8; i
++) {
475 qsort(array
,SIZE(array
),sizeof(array
[0]),
476 (int (*)(const void *,const void *)) verify_sun_cmp
);
477 if (array
[0] == -1) {
478 printf(_("No partitions defined\n"));
481 stop
= cylinders
* heads
* sectors
;
482 if (starts
[array
[0]])
483 printf(_("Unused gap - sectors 0-%d\n"),starts
[array
[0]]);
484 for (i
= 0; i
< 7 && array
[i
+1] != -1; i
++) {
485 printf(_("Unused gap - sectors %d-%d\n"),starts
[array
[i
]]+lens
[array
[i
]],starts
[array
[i
+1]]);
487 start
= starts
[array
[i
]]+lens
[array
[i
]];
489 printf(_("Unused gap - sectors %d-%d\n"),start
,stop
);
493 add_sun_partition(int n
, int sys
) {
494 uint start
, stop
, stop2
;
495 uint starts
[8], lens
[8];
501 if (sunlabel
->partitions
[n
].num_sectors
&& sunlabel
->infos
[n
].id
) {
502 printf(_("Partition %d is already defined. Delete "
503 "it before re-adding it.\n"), n
+ 1);
507 fetch_sun(starts
,lens
,&start
,&stop
);
512 printf(_("Other partitions already cover the whole disk.\nDelete "
513 "some/shrink them before retry.\n"));
517 sprintf(mesg
, _("First %s"), str_units(SINGULAR
));
520 first
= read_int(0, 0, 0, 0, mesg
);
522 first
= read_int(scround(start
), scround(stop
)+1,
523 scround(stop
), 0, mesg
);
524 if (display_in_cyl_units
)
525 first
*= units_per_sector
;
527 /* Starting sector has to be properly aligned */
528 first
= (first
+ heads
* sectors
- 1) / (heads
* sectors
);
529 if (n
== 2 && first
!= 0)
531 It is highly recommended that the third partition covers the whole disk\n\
532 and is of type `Whole disk'\n");
533 for (i
= 0; i
< partitions
; i
++)
534 if (lens
[i
] && starts
[i
] <= first
535 && starts
[i
] + lens
[i
] > first
)
537 if (i
< partitions
&& !whole_disk
) {
538 if (n
== 2 && !first
) {
542 printf(_("Sector %d is already allocated\n"), first
);
546 stop
= cylinders
* heads
* sectors
;
548 for (i
= 0; i
< partitions
; i
++) {
549 if (starts
[i
] > first
&& starts
[i
] < stop
)
552 sprintf(mesg
, _("Last %s or +size or +sizeM or +sizeK"), str_units(SINGULAR
));
554 last
= read_int(scround(stop2
), scround(stop2
), scround(stop2
),
556 else if (n
== 2 && !first
)
557 last
= read_int(scround(first
), scround(stop2
), scround(stop2
),
558 scround(first
), mesg
);
560 last
= read_int(scround(first
), scround(stop
), scround(stop
),
561 scround(first
), mesg
);
562 if (display_in_cyl_units
)
563 last
*= units_per_sector
;
564 if (n
== 2 && !first
) {
568 } else if (last
> stop
) {
570 _("You haven't covered the whole disk with the 3rd partition, but your value\n"
571 "%d %s covers some other partition. Your entry has been changed\n"
573 scround(last
), str_units(SINGULAR
),
574 scround(stop
), str_units(SINGULAR
));
577 } else if (!whole_disk
&& last
> stop
)
580 if (whole_disk
) sys
= WHOLE_DISK
;
581 set_sun_partition(n
, first
, last
, sys
);
585 sun_delete_partition(int i
) {
586 if (i
== 2 && sunlabel
->infos
[i
].id
== WHOLE_DISK
&&
587 !sunlabel
->partitions
[i
].start_cylinder
&&
588 SSWAP32(sunlabel
->partitions
[i
].num_sectors
)
589 == heads
* sectors
* cylinders
)
590 printf(_("If you want to maintain SunOS/Solaris compatibility, "
591 "consider leaving this\n"
592 "partition as Whole disk (5), starting at 0, with %u "
594 (uint
) SSWAP32(sunlabel
->partitions
[i
].num_sectors
));
595 sunlabel
->infos
[i
].id
= 0;
596 sunlabel
->partitions
[i
].num_sectors
= 0;
600 sun_change_sysid(int i
, int sys
) {
601 if (sys
== LINUX_SWAP
&& !sunlabel
->partitions
[i
].start_cylinder
) {
603 _("It is highly recommended that the partition at offset 0\n"
604 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
605 "there may destroy your partition table and bootblock.\n"
606 "Type YES if you're very sure you would like that partition\n"
607 "tagged with 82 (Linux swap): "));
608 if (strcmp (line_ptr
, "YES\n"))
614 /* swaps are not mountable by default */
615 sunlabel
->infos
[i
].flags
|= 0x01;
618 /* assume other types are mountable;
619 user can change it anyway */
620 sunlabel
->infos
[i
].flags
&= ~0x01;
623 sunlabel
->infos
[i
].id
= sys
;
627 sun_list_table(int xtra
) {
631 w
= strlen(disk_device
);
634 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
635 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
636 "%d extra sects/cyl, interleave %d:1\n"
638 "Units = %s of %d * 512 bytes\n\n"),
639 disk_device
, heads
, sectors
, SSWAP16(sunlabel
->rspeed
),
640 cylinders
, SSWAP16(sunlabel
->nacyl
),
641 SSWAP16(sunlabel
->pcylcount
),
642 SSWAP16(sunlabel
->sparecyl
),
643 SSWAP16(sunlabel
->ilfact
),
645 str_units(PLURAL
), units_per_sector
);
648 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
649 "Units = %s of %d * 512 bytes\n\n"),
650 disk_device
, heads
, sectors
, cylinders
,
651 str_units(PLURAL
), units_per_sector
);
653 printf(_("%*s Flag Start End Blocks Id System\n"),
655 for (i
= 0 ; i
< partitions
; i
++) {
656 if (sunlabel
->partitions
[i
].num_sectors
) {
657 __u32 start
= SSWAP32(sunlabel
->partitions
[i
].start_cylinder
) * heads
* sectors
;
658 __u32 len
= SSWAP32(sunlabel
->partitions
[i
].num_sectors
);
660 "%*s%-2d %c%c %9ld %9ld %9ld%c %2x %s\n",
661 /* device */ w
, disk_device
, i
+ 1,
662 /* flags */ (sunlabel
->infos
[i
].flags
& 0x01) ? 'u' : ' ',
663 (sunlabel
->infos
[i
].flags
& 0x10) ? 'r' : ' ',
664 /* start */ (long) scround(start
),
665 /* end */ (long) scround(start
+len
),
666 /* odd flag on end */ (long) len
/ 2, len
& 1 ? '+' : ' ',
667 /* type id */ sunlabel
->infos
[i
].id
,
668 /* type name */ (type
= partition_type(sunlabel
->infos
[i
].id
))
669 ? type
: _("Unknown"));
675 sun_set_alt_cyl(void) {
677 SSWAP16(read_int(0,SSWAP16(sunlabel
->nacyl
), 65535, 0,
678 _("Number of alternate cylinders")));
682 sun_set_ncyl(int cyl
) {
683 sunlabel
->ncyl
= SSWAP16(cyl
);
689 SSWAP16(read_int(0, SSWAP16(sunlabel
->sparecyl
), sectors
, 0,
690 _("Extra sectors per cylinder")));
694 sun_set_ilfact(void) {
696 SSWAP16(read_int(1, SSWAP16(sunlabel
->ilfact
), 32, 0,
697 _("Interleave factor")));
701 sun_set_rspeed(void) {
703 SSWAP16(read_int(1, SSWAP16(sunlabel
->rspeed
), 100000, 0,
704 _("Rotation speed (rpm)")));
708 sun_set_pcylcount(void) {
709 sunlabel
->pcylcount
=
710 SSWAP16(read_int(0, SSWAP16(sunlabel
->pcylcount
), 65535, 0,
711 _("Number of physical cylinders")));
715 sun_write_table(void) {
716 unsigned short *ush
= (unsigned short *)sunlabel
;
717 unsigned short csum
= 0;
719 while(ush
< (unsigned short *)(&sunlabel
->csum
))
721 sunlabel
->csum
= csum
;
722 if (lseek(fd
, 0, SEEK_SET
) < 0)
723 fatal(unable_to_seek
);
724 if (write(fd
, sunlabel
, SECTOR_SIZE
) != SECTOR_SIZE
)
725 fatal(unable_to_write
);