5 * Copyright (C) Andreas Neuper, Sep 1998.
6 * This file may be modified and redistributed under
7 * the terms of the GNU Public License.
9 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
10 * Internationalization
12 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
15 #include <stdio.h> /* stderr */
16 #include <stdlib.h> /* exit */
17 #include <string.h> /* strstr */
18 #include <unistd.h> /* write */
19 #include <sys/ioctl.h> /* ioctl */
20 #include <sys/stat.h> /* stat */
21 #include <assert.h> /* assert */
31 #include "fdisksgilabel.h"
33 static int other_endian = 0;
35 static short volumes=1;
38 * only dealing with free blocks here
41 typedef struct { unsigned int first; unsigned int last; } freeblocks;
42 static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
45 setfreelist(int i, unsigned int f, unsigned int l) {
47 freelist[i].first = f;
53 add2freelist(unsigned int f, unsigned int l) {
56 if (freelist[i].last == 0)
65 for (i = 0; i < 17 ; i++)
70 isinfreelist(unsigned int b) {
73 for (i = 0; i < 17 ; i++)
74 if (freelist[i].first <= b && freelist[i].last >= b)
75 return freelist[i].last;
78 /* return last vacant block of this stride (never 0). */
79 /* the '>=' is not quite correct, but simplifies the code */
81 * end of free blocks section
83 struct systypes sgi_sys_types[] = {
84 {SGI_VOLHDR, N_("SGI volhdr")},
85 {0x01, N_("SGI trkrepl")},
86 {0x02, N_("SGI secrepl")},
87 {SGI_SWAP, N_("SGI raw")},
88 {0x04, N_("SGI bsd")},
89 {0x05, N_("SGI sysv")},
90 {ENTIRE_DISK, N_("SGI volume")},
91 {SGI_EFS, N_("SGI efs")},
92 {0x08, N_("SGI lvol")},
93 {0x09, N_("SGI rlvol")},
94 {SGI_XFS, N_("SGI xfs")},
95 {SGI_XFSLOG, N_("SGI xfslog")},
96 {SGI_XLV, N_("SGI xlv")},
97 {SGI_XVM, N_("SGI xvm")},
98 {LINUX_SWAP, N_("Linux swap")},
99 {LINUX_NATIVE, N_("Linux native")},
100 {LINUX_LVM, N_("Linux LVM")},
101 {LINUX_RAID, N_("Linux RAID")},
106 sgi_get_nsect(void) {
107 return SSWAP16(sgilabel->devparam.nsect);
111 sgi_get_ntrks(void) {
112 return SSWAP16(sgilabel->devparam.ntrks);
117 sgi_get_head_vol0(void) {
118 return SSWAP16(sgilabel->devparam.head_vol0);
122 sgi_get_bytes(void) {
123 return SSWAP16(sgilabel->devparam.bytes);
127 sgi_get_pcylcount(void) {
128 return SSWAP16(sgilabel->devparam.pcylcount);
139 two_s_complement_32bit_sum(unsigned int *base, int size /* in bytes */) {
141 unsigned int sum = 0;
143 size /= sizeof(unsigned int);
144 for (i = 0; i < size; i++)
145 sum -= SSWAP32(base[i]);
151 if (sizeof(sgilabel) > 512) {
153 _("According to MIPS Computer Systems, Inc the "
154 "Label must not contain more than 512 bytes\n"));
158 if (sgilabel->magic != SGI_LABEL_MAGIC &&
159 sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
164 other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
166 * test for correct checksum
168 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
169 sizeof(*sgilabel))) {
171 _("Detected sgi disklabel with wrong checksum.\n"));
174 disklabel = SGI_LABEL;
181 sgi_list_table(int xtra) {
183 int kpi = 0; /* kernel partition ID */
186 w = strlen(disk_device);
189 printf(_("\nDisk %s (SGI disk label): %d heads, %llu sectors\n"
190 "%d cylinders, %d physical cylinders\n"
191 "%d extra sects/cyl, interleave %d:1\n"
193 "Units = %s of %d * %d bytes\n\n"),
194 disk_device, heads, sectors, cylinders,
195 SSWAP16(sgiparam.pcylcount),
196 SSWAP16(sgiparam.sparecyl),
197 SSWAP16(sgiparam.ilfact),
199 str_units(PLURAL), units_per_sector,
202 printf(_("\nDisk %s (SGI disk label): "
203 "%d heads, %llu sectors, %d cylinders\n"
204 "Units = %s of %d * %d bytes\n\n"),
205 disk_device, heads, sectors, cylinders,
206 str_units(PLURAL), units_per_sector,
209 printf(_("----- partitions -----\n"
210 "Pt# %*s Info Start End Sectors Id System\n"),
212 for (i = 0 ; i < partitions; i++) {
213 if (sgi_get_num_sectors(i) || debug) {
214 uint32_t start = sgi_get_start_sector(i);
215 uint32_t len = sgi_get_num_sectors(i);
216 kpi++; /* only count nonempty partitions */
218 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
219 /* fdisk part number */ i+1,
220 /* device */ partname(disk_device, kpi, w+2),
221 /* flags */ (sgi_get_swappartition() == i) ? "swap" :
222 /* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
223 /* start */ (long) scround(start),
224 /* end */ (long) scround(start+len)-1,
225 /* no odd flag on end */ (long) len,
226 /* type id */ sgi_get_sysid(i),
227 /* type name */ (type = partition_type(sgi_get_sysid(i)))
228 ? type : _("Unknown"));
231 printf(_("----- Bootinfo -----\nBootfile: %s\n"
232 "----- Directory Entries -----\n"),
233 sgilabel->boot_file);
234 for (i = 0 ; i < volumes; i++) {
235 if (sgilabel->directory[i].vol_file_size) {
236 uint32_t start = SSWAP32(sgilabel->directory[i].vol_file_start);
237 uint32_t len = SSWAP32(sgilabel->directory[i].vol_file_size);
238 unsigned char *name = sgilabel->directory[i].vol_file_name;
239 printf(_("%2d: %-10s sector%5u size%8u\n"),
240 i, name, (unsigned int) start,
247 sgi_get_start_sector(int i) {
248 return SSWAP32(sgilabel->partitions[i].start_sector);
252 sgi_get_num_sectors(int i) {
253 return SSWAP32(sgilabel->partitions[i].num_sectors);
259 return SSWAP32(sgilabel->partitions[i].id);
263 sgi_get_bootpartition(void)
265 return SSWAP16(sgilabel->boot_part);
269 sgi_get_swappartition(void)
271 return SSWAP16(sgilabel->swap_part);
275 sgi_set_bootpartition(int i)
277 sgilabel->boot_part = SSWAP16(((short)i));
281 sgi_get_lastblock(void) {
282 return heads * sectors * cylinders;
286 sgi_set_swappartition(int i) {
287 sgilabel->swap_part = SSWAP16(((short)i));
291 sgi_check_bootfile(const char* aFile) {
292 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
293 printf(_("\nInvalid Bootfile!\n"
294 "\tThe bootfile must be an absolute non-zero pathname,\n"
295 "\te.g. \"/unix\" or \"/unix.save\".\n"));
298 if (strlen(aFile) > 16) {
299 printf(_("\n\tName of Bootfile too long: "
300 "16 bytes maximum.\n"));
303 if (aFile[0] != '/') {
304 printf(_("\n\tBootfile must have a "
305 "fully qualified pathname.\n"));
310 if (strncmp(aFile, (char *) sgilabel->boot_file, 16)) {
311 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
312 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
313 /* filename is correct and did change */
316 return 0; /* filename did not change */
320 sgi_get_bootfile(void) {
321 return (char *) sgilabel->boot_file;
325 sgi_set_bootfile(const char* aFile) {
327 if (sgi_check_bootfile(aFile)) {
330 if ((aFile[i] != '\n') /* in principle caught again by next line */
331 && (strlen(aFile) > i))
332 sgilabel->boot_file[i] = aFile[i];
334 sgilabel->boot_file[i] = 0;
337 printf(_("\n\tBootfile is changed to \"%s\".\n"),
338 sgilabel->boot_file);
343 create_sgiinfo(void) {
344 /* I keep SGI's habit to write the sgilabel to the second block */
345 sgilabel->directory[0].vol_file_start = SSWAP32(2);
346 sgilabel->directory[0].vol_file_size = SSWAP32(sizeof(sgiinfo));
347 strncpy((char *) sgilabel->directory[0].vol_file_name, "sgilabel", 8);
350 sgiinfo *fill_sgiinfo(void);
353 sgi_write_table(void) {
355 sgilabel->csum = SSWAP32(two_s_complement_32bit_sum(
356 (unsigned int*)sgilabel,
358 assert(two_s_complement_32bit_sum(
359 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
360 if (lseek(fd, 0, SEEK_SET) < 0)
361 fatal(unable_to_seek);
362 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
363 fatal(unable_to_write);
364 if (! strncmp((char *) sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
366 * keep this habit of first writing the "sgilabel".
367 * I never tested whether it works without (AN 981002).
369 sgiinfo *info = fill_sgiinfo();
370 int infostartblock = SSWAP32(sgilabel->directory[0].vol_file_start);
371 if (lseek(fd, (off_t) infostartblock*
372 SECTOR_SIZE, SEEK_SET) < 0)
373 fatal(unable_to_seek);
374 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
375 fatal(unable_to_write);
381 compare_start(int *x, int *y) {
383 * sort according to start sectors
384 * and prefers largest partition:
385 * entry zero is entire disk entry
389 unsigned int a = sgi_get_start_sector(i);
390 unsigned int b = sgi_get_start_sector(j);
391 unsigned int c = sgi_get_num_sectors(i);
392 unsigned int d = sgi_get_num_sectors(j);
395 return (d > c) ? 1 : (d == c) ? 0 : -1;
396 return (a > b) ? 1 : -1;
403 * = 0 : disk is properly filled to the rim
404 * < 0 : there is an overlap
405 * > 0 : there is still some vacant space
407 return verify_sgi(0);
411 verify_sgi(int verbose)
413 int Index[16]; /* list of valid partitions */
414 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
415 int entire = 0, i = 0;
416 unsigned int start = 0;
417 long long gap = 0; /* count unused blocks */
418 unsigned int lastblock = sgi_get_lastblock();
421 for (i=0; i<16; i++) {
422 if (sgi_get_num_sectors(i) != 0) {
423 Index[sortcount++]=i;
424 if (sgi_get_sysid(i) == ENTIRE_DISK) {
427 printf(_("More than one entire disk entry present.\n"));
432 if (sortcount == 0) {
434 printf(_("No partitions defined\n"));
435 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
437 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
438 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
439 if ((Index[0] != 10) && verbose)
440 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
441 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
442 printf(_("The entire disk partition should start "
444 "not at diskblock %d.\n"),
445 sgi_get_start_sector(Index[0]));
446 if (debug) /* I do not understand how some disks fulfil it */
447 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
448 printf(_("The entire disk partition is only %d diskblock large,\n"
449 "but the disk is %d diskblocks long.\n"),
450 sgi_get_num_sectors(Index[0]), lastblock);
451 lastblock = sgi_get_num_sectors(Index[0]);
454 printf(_("One Partition (#11) should cover the entire disk.\n"));
456 printf("sysid=%d\tpartition=%d\n",
457 sgi_get_sysid(Index[0]), Index[0]+1);
459 for (i=1, start=0; i<sortcount; i++) {
460 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
461 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
462 if (debug) /* I do not understand how some disks fulfil it */
464 printf(_("Partition %d does not start on cylinder boundary.\n"),
467 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
468 if (debug) /* I do not understand how some disks fulfil it */
470 printf(_("Partition %d does not end on cylinder boundary.\n"),
473 /* We cannot handle several "entire disk" entries. */
474 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
475 if (start > sgi_get_start_sector(Index[i])) {
477 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
478 Index[i-1]+1, Index[i]+1,
479 start - sgi_get_start_sector(Index[i]));
480 if (gap > 0) gap = -gap;
481 if (gap == 0) gap = -1;
483 if (start < sgi_get_start_sector(Index[i])) {
485 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
486 sgi_get_start_sector(Index[i]) - start,
487 start, sgi_get_start_sector(Index[i])-1);
488 gap += sgi_get_start_sector(Index[i]) - start;
489 add2freelist(start, sgi_get_start_sector(Index[i]));
491 start = sgi_get_start_sector(Index[i])
492 + sgi_get_num_sectors(Index[i]);
493 /* Align free space on cylinder boundary */
495 start += cylsize - (start % cylsize);
498 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
499 sgi_get_start_sector(Index[i]),
500 sgi_get_num_sectors(Index[i]),
501 sgi_get_sysid(Index[i]));
504 if (start < lastblock) {
506 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
507 lastblock - start, start, lastblock-1);
508 gap += lastblock - start;
509 add2freelist(start, lastblock);
512 * Done with arithmetics
516 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
517 printf(_("\nThe boot partition does not exist.\n"));
519 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
520 printf(_("\nThe swap partition does not exist.\n"));
522 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
523 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
524 printf(_("\nThe swap partition has no swap type.\n"));
526 if (sgi_check_bootfile("/unix"))
527 printf(_("\tYou have chosen an unusual boot file name.\n"));
529 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
533 sgi_change_sysid(int i, int sys)
535 if (sgi_get_num_sectors(i) == 0) /* caught already before, ... */ {
536 printf(_("Sorry, only for non-empty partitions you can change the tag.\n"));
539 if (((sys != ENTIRE_DISK) && (sys != SGI_VOLHDR))
540 && (sgi_get_start_sector(i)<1)) {
542 _("It is highly recommended that the partition at offset 0\n"
543 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
544 "retrieve from its directory standalone tools like sash and fx.\n"
545 "Only the \"SGI volume\" entire disk section may violate this.\n"
546 "Type YES if you are sure about tagging this partition differently.\n"));
547 if (strcmp (line_ptr, _("YES\n")))
550 sgilabel->partitions[i].id = SSWAP32(sys);
554 /* returns partition index of first entry marked as entire disk */
560 if (sgi_get_sysid(i) == SGI_VOLUME)
566 sgi_set_partition(int i, unsigned int start, unsigned int length, int sys) {
567 sgilabel->partitions[i].id = SSWAP32(sys);
568 sgilabel->partitions[i].num_sectors = SSWAP32(length);
569 sgilabel->partitions[i].start_sector = SSWAP32(start);
571 if (sgi_gaps() < 0) /* rebuild freelist */
572 printf(_("Do You know, You got a partition overlap on the disk?\n"));
576 sgi_set_entire(void) {
579 for (n=10; n<partitions; n++) {
580 if (!sgi_get_num_sectors(n)) {
581 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
593 for (n=8; n<partitions; n++) {
594 if (!sgi_get_num_sectors(n)) {
596 * Choose same default volume header size
599 if (4096 < sgi_get_lastblock())
600 sgi_set_partition(n, 0, 4096, SGI_VOLHDR);
607 sgi_delete_partition(int i)
609 sgi_set_partition(i, 0, 0, 0);
613 sgi_add_partition(int n, int sys)
616 unsigned int first=0, last=0;
623 if (sgi_get_num_sectors(n)) {
624 printf(_("Partition %d is already defined. Delete "
625 "it before re-adding it.\n"), n + 1);
628 if ((sgi_entire() == -1)
629 && (sys != SGI_VOLUME)) {
630 printf(_("Attempting to generate entire disk entry automatically.\n"));
634 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
635 printf(_("The entire disk is already covered with partitions.\n"));
638 if (sgi_gaps() < 0) {
639 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
642 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
644 if (sys == SGI_VOLUME) {
645 last = sgi_get_lastblock();
646 first = read_int(0, 0, last-1, 0, mesg);
648 printf(_("It is highly recommended that eleventh partition\n"
649 "covers the entire disk and is of type `SGI volume'\n"));
652 first = freelist[0].first;
653 last = freelist[0].last;
654 first = read_int(scround(first), scround(first), scround(last)-1,
657 if (display_in_cyl_units)
658 first *= units_per_sector;
660 first = first; /* align to cylinder if you know how ... */
662 last = isinfreelist(first);
664 printf(_("You will get a partition overlap on the disk. "
669 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
670 last = read_int(scround(first), scround(last)-1, scround(last)-1,
671 scround(first), mesg)+1;
672 if (display_in_cyl_units)
673 last *= units_per_sector;
675 last = last; /* align to cylinder if You know how ... */
676 if ((sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock()))
677 printf(_("It is highly recommended that eleventh partition\n"
678 "covers the entire disk and is of type `SGI volume'\n"));
679 sgi_set_partition(n, first, last-first, sys);
683 create_sgilabel(void)
685 struct hd_geometry geometry;
692 unsigned long long llsectors;
693 int res; /* the result from the ioctl */
694 int sec_fac; /* the sector factor */
696 sec_fac = sector_size / 512; /* determine the sector factor */
699 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
700 "until you decide to write them. After that, of course, the previous\n"
701 "content will be unrecoverably lost.\n\n"));
703 other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
705 res = blkdev_get_sectors(fd, &llsectors);
708 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
709 heads = geometry.heads;
710 sectors = geometry.sectors;
712 /* the get device size ioctl was successful */
713 unsigned long long llcyls;
714 llcyls = llsectors / (heads * sectors * sec_fac);
716 if (cylinders != llcyls) /* truncated? */
719 /* otherwise print error and use truncated version */
720 cylinders = geometry.cylinders;
722 _("Warning: BLKGETSIZE ioctl failed on %s. "
723 "Using geometry cylinder value of %d.\n"
724 "This value may be truncated for devices"
725 " > 33.8 GB.\n"), disk_device, cylinders);
729 for (i = 0; i < 4; i++) {
731 if (valid_part_table_flag(MBRbuffer)) {
732 if (get_part_table(i)->sys_ind) {
733 old[i].sysid = get_part_table(i)->sys_ind;
734 old[i].start = get_start_sect(get_part_table(i));
735 old[i].nsect = get_nr_sects(get_part_table(i));
736 printf(_("Trying to keep parameters of partition %d.\n"), i);
738 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
739 old[i].sysid, old[i].start, old[i].nsect);
744 zeroize_mbr_buffer();
745 sgilabel->magic = SSWAP32(SGI_LABEL_MAGIC);
746 sgilabel->boot_part = SSWAP16(0);
747 sgilabel->swap_part = SSWAP16(1);
749 /* sizeof(sgilabel->boot_file) = 16 > 6 */
750 memset(sgilabel->boot_file, 0, 16);
751 strcpy((char *) sgilabel->boot_file, "/unix");
753 sgilabel->devparam.skew = (0);
754 sgilabel->devparam.gap1 = (0);
755 sgilabel->devparam.gap2 = (0);
756 sgilabel->devparam.sparecyl = (0);
757 sgilabel->devparam.pcylcount = SSWAP16(geometry.cylinders);
758 sgilabel->devparam.head_vol0 = SSWAP16(0);
759 sgilabel->devparam.ntrks = SSWAP16(geometry.heads);
760 /* tracks/cylinder (heads) */
761 sgilabel->devparam.cmd_tag_queue_depth = (0);
762 sgilabel->devparam.unused0 = (0);
763 sgilabel->devparam.unused1 = SSWAP16(0);
764 sgilabel->devparam.nsect = SSWAP16(geometry.sectors);
766 sgilabel->devparam.bytes = SSWAP16(sector_size);
767 sgilabel->devparam.ilfact = SSWAP16(1);
768 sgilabel->devparam.flags = SSWAP32(TRACK_FWD|\
769 IGNORE_ERRORS|RESEEK);
770 sgilabel->devparam.datarate = SSWAP32(0);
771 sgilabel->devparam.retries_on_error = SSWAP32(1);
772 sgilabel->devparam.ms_per_word = SSWAP32(0);
773 sgilabel->devparam.xylogics_gap1 = SSWAP16(0);
774 sgilabel->devparam.xylogics_syncdelay = SSWAP16(0);
775 sgilabel->devparam.xylogics_readdelay = SSWAP16(0);
776 sgilabel->devparam.xylogics_gap2 = SSWAP16(0);
777 sgilabel->devparam.xylogics_readgate = SSWAP16(0);
778 sgilabel->devparam.xylogics_writecont = SSWAP16(0);
779 memset(&(sgilabel->directory), 0, sizeof(struct volume_directory)*15);
780 memset(&(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16);
781 disklabel = SGI_LABEL;
786 for (i = 0; i < 4; i++) {
788 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
796 /* do nothing in the beginning */
802 /* do nothing in the beginning */
806 sgi_set_pcylcount(void)
808 /* do nothing in the beginning */
814 /* do nothing in the beginning */
820 /* do nothing in the beginning */
823 /* _____________________________________________________________
829 sgiinfo *info=xcalloc(1, sizeof(sgiinfo));
830 info->magic=SSWAP32(SGI_INFO_MAGIC);
831 info->b1=SSWAP32(-1);
832 info->b2=SSWAP16(-1);
834 /* You may want to replace this string !!!!!!! */
835 strcpy((char *) info->scsi_string, "IBM OEM 0662S12 3 30");
836 strcpy((char *) info->serial, "0000");
837 info->check1816 = SSWAP16(18*256 +16);
838 strcpy((char *) info->installer, "Sfx version 5.3, Oct 18, 1994");