Upload Tizen:Base source
[framework/base/util-linux-ng.git] / fdisk / fdisksgilabel.c
1 /*
2  *
3  * fdisksgilabel.c
4  *
5  * Copyright (C) Andreas Neuper, Sep 1998.
6  *      This file may be modified and redistributed under
7  *      the terms of the GNU Public License.
8  *
9  * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
10  *      Internationalization
11  *
12  * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
13  *      Some fixes
14  */
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 */
22
23 #include <endian.h>
24 #include "nls.h"
25
26 #include "blkdev.h"
27
28 #include "common.h"
29 #include "fdisk.h"
30 #include "fdisksgilabel.h"
31
32 static  int     other_endian = 0;
33 static  int     debug = 0;
34 static  short volumes=1;
35
36 /*
37  * only dealing with free blocks here
38  */
39
40 typedef struct { unsigned int first; unsigned int last; } freeblocks;
41 static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
42
43 static void
44 setfreelist(int i, unsigned int f, unsigned int l) {
45         freelist[i].first = f;
46         freelist[i].last = l;
47 }
48
49 static void
50 add2freelist(unsigned int f, unsigned int l) {
51         int i = 0;
52         for ( ; i < 17 ; i++)
53                 if (freelist[i].last == 0)
54                         break;
55         setfreelist(i, f, l);
56 }
57
58 static void
59 clearfreelist(void) {
60         int i;
61
62         for (i = 0; i < 17 ; i++)
63                 setfreelist(i, 0, 0);
64 }
65
66 static unsigned int
67 isinfreelist(unsigned int b) {
68         int i;
69
70         for (i = 0; i < 17 ; i++)
71                 if (freelist[i].first <= b && freelist[i].last >= b)
72                         return freelist[i].last;
73         return 0;
74 }
75         /* return last vacant block of this stride (never 0). */
76         /* the '>=' is not quite correct, but simplifies the code */
77 /*
78  * end of free blocks section
79  */
80 struct systypes sgi_sys_types[] = {
81         {SGI_VOLHDR,    N_("SGI volhdr")},
82         {0x01,          N_("SGI trkrepl")},
83         {0x02,          N_("SGI secrepl")},
84         {SGI_SWAP,      N_("SGI raw")},
85         {0x04,          N_("SGI bsd")},
86         {0x05,          N_("SGI sysv")},
87         {ENTIRE_DISK,   N_("SGI volume")},
88         {SGI_EFS,       N_("SGI efs")},
89         {0x08,          N_("SGI lvol")},
90         {0x09,          N_("SGI rlvol")},
91         {SGI_XFS,       N_("SGI xfs")},
92         {SGI_XFSLOG,    N_("SGI xfslog")},
93         {SGI_XLV,       N_("SGI xlv")},
94         {SGI_XVM,       N_("SGI xvm")},
95         {LINUX_SWAP,    N_("Linux swap")},
96         {LINUX_NATIVE,  N_("Linux native")},
97         {LINUX_LVM,     N_("Linux LVM")},
98         {LINUX_RAID,    N_("Linux RAID")},
99         {0, NULL }
100 };
101
102 static inline unsigned short
103 __swap16(unsigned short x) {
104         return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
105 }
106
107 static inline uint32_t
108 __swap32(uint32_t x) {
109         return (((x & 0xFF) << 24) |
110                 ((x & 0xFF00) << 8) |
111                 ((x & 0xFF0000) >> 8) |
112                 ((x & 0xFF000000) >> 24));
113 }
114
115 static int
116 sgi_get_nsect(void) {
117         return SSWAP16(sgilabel->devparam.nsect);
118 }
119
120 static int
121 sgi_get_ntrks(void) {
122         return SSWAP16(sgilabel->devparam.ntrks);
123 }
124
125 #if 0
126 static int
127 sgi_get_head_vol0(void) {
128         return SSWAP16(sgilabel->devparam.head_vol0);
129 }
130
131 static int
132 sgi_get_bytes(void) {
133         return SSWAP16(sgilabel->devparam.bytes);
134 }
135
136 static int
137 sgi_get_pcylcount(void) {
138         return SSWAP16(sgilabel->devparam.pcylcount);
139 }
140 #endif
141
142 void
143 sgi_nolabel() {
144         sgilabel->magic = 0;
145         sgi_label = 0;
146         partitions = 4;
147 }
148
149 static unsigned int
150 two_s_complement_32bit_sum(unsigned int *base, int size /* in bytes */) {
151         int i = 0;
152         unsigned int sum = 0;
153
154         size /= sizeof(unsigned int);
155         for (i = 0; i < size; i++)
156                 sum -= SSWAP32(base[i]);
157         return sum;
158 }
159
160 int
161 check_sgi_label() {
162         if (sizeof(sgilabel) > 512) {
163                 fprintf(stderr,
164                         _("According to MIPS Computer Systems, Inc the "
165                           "Label must not contain more than 512 bytes\n"));
166                 exit(1);
167         }
168
169         if (sgilabel->magic != SGI_LABEL_MAGIC &&
170             sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
171                 sgi_label = 0;
172                 other_endian = 0;
173                 return 0;
174         }
175
176         other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
177         /*
178          * test for correct checksum
179          */
180         if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
181                                        sizeof(*sgilabel))) {
182                 fprintf(stderr,
183                         _("Detected sgi disklabel with wrong checksum.\n"));
184         }
185         update_units();
186         sgi_label = 1;
187         partitions= 16;
188         volumes = 15;
189         return 1;
190 }
191
192 void
193 sgi_list_table(int xtra) {
194         int i, w;
195         int kpi = 0;            /* kernel partition ID */
196         char *type;
197
198         w = strlen(disk_device);
199
200         if (xtra) {
201                 printf(_("\nDisk %s (SGI disk label): %d heads, %llu sectors\n"
202                          "%d cylinders, %d physical cylinders\n"
203                          "%d extra sects/cyl, interleave %d:1\n"
204                          "%s\n"
205                          "Units = %s of %d * %d bytes\n\n"),
206                        disk_device, heads, sectors, cylinders,
207                        SSWAP16(sgiparam.pcylcount),
208                        SSWAP16(sgiparam.sparecyl),
209                        SSWAP16(sgiparam.ilfact),
210                        (char *)sgilabel,
211                        str_units(PLURAL), units_per_sector,
212                        sector_size);
213         } else {
214                 printf(_("\nDisk %s (SGI disk label): "
215                          "%d heads, %llu sectors, %d cylinders\n"
216                          "Units = %s of %d * %d bytes\n\n"),
217                        disk_device, heads, sectors, cylinders,
218                        str_units(PLURAL), units_per_sector,
219                        sector_size);
220         }
221         printf(_("----- partitions -----\n"
222                  "Pt# %*s  Info     Start       End   Sectors  Id  System\n"),
223                w + 1, _("Device"));
224         for (i = 0 ; i < partitions; i++) {
225                 if (sgi_get_num_sectors(i) || debug) {
226                         uint32_t start = sgi_get_start_sector(i);
227                         uint32_t len = sgi_get_num_sectors(i);
228                         kpi++;          /* only count nonempty partitions */
229                         printf(
230                                 "%2d: %s %4s %9ld %9ld %9ld  %2x  %s\n",
231 /* fdisk part number */   i+1,
232 /* device */              partname(disk_device, kpi, w+2),
233 /* flags */               (sgi_get_swappartition() == i) ? "swap" :
234 /* flags */               (sgi_get_bootpartition() == i) ? "boot" : "    ", 
235 /* start */               (long) scround(start),
236 /* end */                 (long) scround(start+len)-1,
237 /* no odd flag on end */  (long) len, 
238 /* type id */             sgi_get_sysid(i),
239 /* type name */           (type = partition_type(sgi_get_sysid(i)))
240                                 ? type : _("Unknown"));
241                 }
242         }
243         printf(_("----- Bootinfo -----\nBootfile: %s\n"
244                  "----- Directory Entries -----\n"),
245                sgilabel->boot_file);
246         for (i = 0 ; i < volumes; i++) {
247                 if (sgilabel->directory[i].vol_file_size) {
248                         uint32_t start = SSWAP32(sgilabel->directory[i].vol_file_start);
249                         uint32_t len = SSWAP32(sgilabel->directory[i].vol_file_size);
250                         unsigned char *name = sgilabel->directory[i].vol_file_name;
251                         printf(_("%2d: %-10s sector%5u size%8u\n"),
252                                i, name, (unsigned int) start,
253                                (unsigned int) len);
254                 }
255         }
256 }
257
258 unsigned int
259 sgi_get_start_sector(int i) {
260         return SSWAP32(sgilabel->partitions[i].start_sector);
261 }
262
263 unsigned int
264 sgi_get_num_sectors(int i) {
265         return SSWAP32(sgilabel->partitions[i].num_sectors);
266 }
267
268 int
269 sgi_get_sysid(int i)
270 {
271         return SSWAP32(sgilabel->partitions[i].id);
272 }
273
274 int
275 sgi_get_bootpartition(void)
276 {
277         return SSWAP16(sgilabel->boot_part);
278 }
279
280 int
281 sgi_get_swappartition(void)
282 {
283         return SSWAP16(sgilabel->swap_part);
284 }
285
286 void
287 sgi_set_bootpartition(int i)
288 {
289         sgilabel->boot_part = SSWAP16(((short)i));
290 }
291
292 static unsigned int
293 sgi_get_lastblock(void) {
294         return heads * sectors * cylinders;
295 }
296
297 void
298 sgi_set_swappartition(int i) {
299         sgilabel->swap_part = SSWAP16(((short)i));
300 }
301
302 static int
303 sgi_check_bootfile(const char* aFile) {
304         if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
305                 printf(_("\nInvalid Bootfile!\n"
306                          "\tThe bootfile must be an absolute non-zero pathname,\n"
307                          "\te.g. \"/unix\" or \"/unix.save\".\n"));
308                 return 0;
309         } else {
310                 if (strlen(aFile) > 16) {
311                         printf(_("\n\tName of Bootfile too long:  "
312                                  "16 bytes maximum.\n"));
313                         return 0;
314                 } else {
315                         if (aFile[0] != '/') {
316                                 printf(_("\n\tBootfile must have a "
317                                          "fully qualified pathname.\n"));
318                                 return 0;
319                         }
320                 }
321         }
322         if (strncmp(aFile, (char *) sgilabel->boot_file, 16)) {
323                 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
324                          "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
325                 /* filename is correct and did change */
326                 return 1;
327         }
328         return 0;       /* filename did not change */
329 }
330
331 const char *
332 sgi_get_bootfile(void) {
333         return (char *) sgilabel->boot_file;
334 }
335
336 void
337 sgi_set_bootfile(const char* aFile) {
338         int i = 0;
339
340         if (sgi_check_bootfile(aFile)) {
341                 while (i < 16) {
342                         if ((aFile[i] != '\n')  /* in principle caught again by next line */
343                             &&  (strlen(aFile) > i))
344                                 sgilabel->boot_file[i] = aFile[i];
345                         else
346                                 sgilabel->boot_file[i] = 0;
347                         i++;
348                 }
349                 printf(_("\n\tBootfile is changed to \"%s\".\n"),
350                        sgilabel->boot_file);
351         }
352 }
353
354 void
355 create_sgiinfo(void) {
356         /* I keep SGI's habit to write the sgilabel to the second block */
357         sgilabel->directory[0].vol_file_start = SSWAP32(2);
358         sgilabel->directory[0].vol_file_size = SSWAP32(sizeof(sgiinfo));
359         strncpy((char *) sgilabel->directory[0].vol_file_name, "sgilabel", 8);
360 }
361
362 sgiinfo *fill_sgiinfo(void);
363
364 void
365 sgi_write_table(void) {
366         sgilabel->csum = 0;
367         sgilabel->csum = SSWAP32(two_s_complement_32bit_sum(
368                 (unsigned int*)sgilabel, 
369                 sizeof(*sgilabel)));
370         assert(two_s_complement_32bit_sum(
371                 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
372         if (lseek(fd, 0, SEEK_SET) < 0)
373                 fatal(unable_to_seek);
374         if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
375                 fatal(unable_to_write);
376         if (! strncmp((char *) sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
377                 /*
378                  * keep this habit of first writing the "sgilabel".
379                  * I never tested whether it works without (AN 981002).
380                  */
381                 sgiinfo *info = fill_sgiinfo();
382                 int infostartblock = SSWAP32(sgilabel->directory[0].vol_file_start);
383                 if (lseek(fd, (off_t) infostartblock*
384                                 SECTOR_SIZE, SEEK_SET) < 0)
385                         fatal(unable_to_seek);
386                 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
387                         fatal(unable_to_write);
388                 free(info);
389         }
390 }
391
392 static int
393 compare_start(int *x, int *y) {
394         /*
395          * sort according to start sectors
396          * and prefers largest partition:
397          * entry zero is entire disk entry
398          */
399         unsigned int i = *x;
400         unsigned int j = *y;
401         unsigned int a = sgi_get_start_sector(i);
402         unsigned int b = sgi_get_start_sector(j);
403         unsigned int c = sgi_get_num_sectors(i);
404         unsigned int d = sgi_get_num_sectors(j);
405
406         if (a == b)
407                 return (d > c) ? 1 : (d == c) ? 0 : -1;
408         return (a > b) ? 1 : -1;
409 }
410
411 static int
412 sgi_gaps(void) {
413         /*
414          * returned value is:
415          *  = 0 : disk is properly filled to the rim
416          *  < 0 : there is an overlap
417          *  > 0 : there is still some vacant space
418          */
419         return verify_sgi(0);
420 }
421
422 int
423 verify_sgi(int verbose)
424 {
425         int Index[16];          /* list of valid partitions */
426         int sortcount = 0;      /* number of used partitions, i.e. non-zero lengths */
427         int entire = 0, i = 0;
428         unsigned int start = 0;
429         long long gap = 0;      /* count unused blocks */
430         unsigned int lastblock = sgi_get_lastblock();
431
432         clearfreelist();
433         for (i=0; i<16; i++) {
434                 if (sgi_get_num_sectors(i) != 0) {
435                         Index[sortcount++]=i;
436                         if (sgi_get_sysid(i) == ENTIRE_DISK) {
437                                 if (entire++ == 1) {
438                                         if (verbose)
439                                                 printf(_("More than one entire disk entry present.\n"));
440                                 }
441                         }
442                 }
443         }
444         if (sortcount == 0) {
445                 if (verbose)
446                         printf(_("No partitions defined\n"));
447                 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
448         }
449         qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
450         if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
451                 if ((Index[0] != 10) && verbose)
452                         printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
453                 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
454                         printf(_("The entire disk partition should start "
455                                  "at block 0,\n"
456                                  "not at diskblock %d.\n"),
457                                sgi_get_start_sector(Index[0]));
458                 if (debug)      /* I do not understand how some disks fulfil it */
459                         if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
460                                 printf(_("The entire disk partition is only %d diskblock large,\n"
461                                          "but the disk is %d diskblocks long.\n"),
462                                        sgi_get_num_sectors(Index[0]), lastblock);
463                 lastblock = sgi_get_num_sectors(Index[0]);
464         } else {
465                 if (verbose)
466                         printf(_("One Partition (#11) should cover the entire disk.\n"));
467                 if (debug>2)
468                         printf("sysid=%d\tpartition=%d\n",
469                                sgi_get_sysid(Index[0]), Index[0]+1);
470         }
471         for (i=1, start=0; i<sortcount; i++) {
472                 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
473                 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
474                         if (debug)      /* I do not understand how some disks fulfil it */
475                                 if (verbose)
476                                         printf(_("Partition %d does not start on cylinder boundary.\n"),
477                                                Index[i]+1);
478                 }
479                 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
480                         if (debug)      /* I do not understand how some disks fulfil it */
481                                 if (verbose)
482                                         printf(_("Partition %d does not end on cylinder boundary.\n"),
483                                                Index[i]+1);
484                 }
485                 /* We cannot handle several "entire disk" entries. */
486                 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
487                 if (start > sgi_get_start_sector(Index[i])) {
488                         if (verbose)
489                                 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
490                                        Index[i-1]+1, Index[i]+1,
491                                        start - sgi_get_start_sector(Index[i]));
492                         if (gap >  0) gap = -gap;
493                         if (gap == 0) gap = -1;
494                 }
495                 if (start < sgi_get_start_sector(Index[i])) {
496                         if (verbose)
497                                 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
498                                        sgi_get_start_sector(Index[i]) - start,
499                                        start, sgi_get_start_sector(Index[i])-1);
500                         gap += sgi_get_start_sector(Index[i]) - start;
501                         add2freelist(start, sgi_get_start_sector(Index[i]));
502                 }
503                 start = sgi_get_start_sector(Index[i])
504                         + sgi_get_num_sectors(Index[i]);
505                 if (debug > 1) {
506                         if (verbose)
507                                 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
508                                        sgi_get_start_sector(Index[i]),
509                                        sgi_get_num_sectors(Index[i]),
510                                        sgi_get_sysid(Index[i]));
511                 }
512         }
513         if (start < lastblock) {
514                 if (verbose)
515                         printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
516                                lastblock - start, start, lastblock-1);
517                 gap += lastblock - start;
518                 add2freelist(start, lastblock);
519         }
520         /*
521          * Done with arithmetics
522          * Go for details now
523          */
524         if (verbose) {
525                 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
526                         printf(_("\nThe boot partition does not exist.\n"));
527                 }
528                 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
529                         printf(_("\nThe swap partition does not exist.\n"));
530                 } else {
531                         if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
532                             &&  (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
533                                 printf(_("\nThe swap partition has no swap type.\n"));
534                 }
535                 if (sgi_check_bootfile("/unix"))
536                         printf(_("\tYou have chosen an unusual boot file name.\n"));
537         }
538         return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
539 }
540
541 int
542 sgi_change_sysid(int i, int sys)
543 {
544         if (sgi_get_num_sectors(i) == 0) /* caught already before, ... */ {
545                 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
546                 return 0;
547         }
548         if (((sys != ENTIRE_DISK) && (sys != SGI_VOLHDR))
549             && (sgi_get_start_sector(i)<1)) {
550                 read_chars(
551                         _("It is highly recommended that the partition at offset 0\n"
552                           "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
553                           "retrieve from its directory standalone tools like sash and fx.\n"
554                           "Only the \"SGI volume\" entire disk section may violate this.\n"
555                           "Type YES if you are sure about tagging this partition differently.\n"));
556                 if (strcmp (line_ptr, _("YES\n")))
557                         return 0;
558         }
559         sgilabel->partitions[i].id = SSWAP32(sys);
560         return 1;
561 }
562
563 /* returns partition index of first entry marked as entire disk */
564 static int
565 sgi_entire(void) {
566         int i;
567
568         for (i=0; i<16; i++)
569                 if (sgi_get_sysid(i) == SGI_VOLUME)
570                         return i;
571         return -1;
572 }
573
574 static void
575 sgi_set_partition(int i, unsigned int start, unsigned int length, int sys) {
576         sgilabel->partitions[i].id = SSWAP32(sys);
577         sgilabel->partitions[i].num_sectors = SSWAP32(length);
578         sgilabel->partitions[i].start_sector = SSWAP32(start);
579         set_changed(i);
580         if (sgi_gaps() < 0)     /* rebuild freelist */
581                 printf(_("Do You know, You got a partition overlap on the disk?\n"));
582 }
583
584 static void
585 sgi_set_entire(void) {
586         int n;
587
588         for (n=10; n<partitions; n++) {
589                 if (!sgi_get_num_sectors(n)) {
590                         sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
591                         break;
592                 }
593         }
594 }
595
596 static
597 void
598 sgi_set_volhdr(void)
599 {
600         int n;
601
602         for (n=8; n<partitions; n++) {
603                 if (!sgi_get_num_sectors(n)) {
604                         /*
605                          * Choose same default volume header size
606                          * as IRIX fx uses.
607                          */
608                         if (4096 < sgi_get_lastblock())
609                                 sgi_set_partition(n, 0, 4096, SGI_VOLHDR);
610                         break;
611                 }
612         }
613 }
614
615 void
616 sgi_delete_partition(int i)
617 {
618         sgi_set_partition(i, 0, 0, 0);
619 }
620
621 void
622 sgi_add_partition(int n, int sys)
623 {
624         char mesg[256];
625         unsigned int first=0, last=0;
626
627         if (n == 10) {
628                 sys = SGI_VOLUME;
629         } else if (n == 8) {
630                 sys = 0;
631         }
632         if (sgi_get_num_sectors(n)) {
633                 printf(_("Partition %d is already defined.  Delete "
634                          "it before re-adding it.\n"), n + 1);
635                 return;
636         }
637         if ((sgi_entire() == -1)
638             &&  (sys != SGI_VOLUME)) {
639                 printf(_("Attempting to generate entire disk entry automatically.\n"));
640                 sgi_set_entire();
641                 sgi_set_volhdr();
642         }
643         if ((sgi_gaps() == 0) &&  (sys != SGI_VOLUME)) {
644                 printf(_("The entire disk is already covered with partitions.\n"));
645                 return;
646         }
647         if (sgi_gaps() < 0) {
648                 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
649                 return;
650         }
651         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
652         for (;;) {
653                 if (sys == SGI_VOLUME) {
654                         last = sgi_get_lastblock();
655                         first = read_int(0, 0, last-1, 0, mesg);
656                         if (first != 0) {
657                                 printf(_("It is highly recommended that eleventh partition\n"
658                                          "covers the entire disk and is of type `SGI volume'\n"));
659                         }
660                 } else {
661                         first = freelist[0].first;
662                         last  = freelist[0].last;
663                         first = read_int(scround(first), scround(first), scround(last)-1,
664                                          0, mesg);
665                 }
666                 if (display_in_cyl_units)
667                         first *= units_per_sector;
668                 else
669                         first = first; /* align to cylinder if you know how ... */
670                 if (!last)
671                         last = isinfreelist(first);
672                 if (last == 0) {
673                         printf(_("You will get a partition overlap on the disk. "
674                                  "Fix it first!\n"));
675                 } else
676                         break;
677         }
678         snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
679         last = read_int(scround(first), scround(last)-1, scround(last)-1,
680                         scround(first), mesg)+1;
681         if (display_in_cyl_units)
682                 last *= units_per_sector;                                     
683         else                                                             
684                 last = last; /* align to cylinder if You know how ... */
685         if ((sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock()))
686                 printf(_("It is highly recommended that eleventh partition\n"
687                          "covers the entire disk and is of type `SGI volume'\n"));
688         sgi_set_partition(n, first, last-first, sys);
689 }
690
691 void
692 create_sgilabel(void)
693 {
694         struct hd_geometry geometry;
695         struct {
696                 unsigned int start;
697                 unsigned int nsect;
698                 int sysid;
699         } old[4];
700         int i=0;
701         unsigned long long llsectors;
702         int res;                /* the result from the ioctl */
703         int sec_fac;            /* the sector factor */
704
705         sec_fac = sector_size / 512;    /* determine the sector factor */
706
707         fprintf(stderr,
708                 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
709                   "until you decide to write them. After that, of course, the previous\n"
710                   "content will be unrecoverably lost.\n\n"));
711
712         other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
713
714         res = blkdev_get_sectors(fd, &llsectors);
715
716 #ifdef HDIO_GETGEO
717         if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
718                 heads = geometry.heads;
719                 sectors = geometry.sectors;
720                 if (res == 0) {
721                         /* the get device size ioctl was successful */
722                         unsigned long long llcyls;
723                         llcyls = llsectors / (heads * sectors * sec_fac);
724                         cylinders = llcyls;
725                         if (cylinders != llcyls)        /* truncated? */
726                                 cylinders = ~0;
727                 } else {
728                         /* otherwise print error and use truncated version */
729                         cylinders = geometry.cylinders;
730                         fprintf(stderr,
731                                 _("Warning:  BLKGETSIZE ioctl failed on %s.  "
732                                   "Using geometry cylinder value of %d.\n"
733                                   "This value may be truncated for devices"
734                                   " > 33.8 GB.\n"), disk_device, cylinders);
735                 }
736         }
737 #endif
738         for (i = 0; i < 4; i++) {
739                 old[i].sysid = 0;
740                 if (valid_part_table_flag(MBRbuffer)) {
741                         if (get_part_table(i)->sys_ind) {
742                                 old[i].sysid = get_part_table(i)->sys_ind;
743                                 old[i].start = get_start_sect(get_part_table(i));
744                                 old[i].nsect = get_nr_sects(get_part_table(i));
745                                 printf(_("Trying to keep parameters of partition %d.\n"), i);
746                                 if (debug)
747                                         printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
748                                                old[i].sysid, old[i].start, old[i].nsect);
749                         }
750                 }
751         }
752
753         memset(MBRbuffer, 0, sizeof(MBRbuffer));
754         sgilabel->magic = SSWAP32(SGI_LABEL_MAGIC);
755         sgilabel->boot_part = SSWAP16(0);
756         sgilabel->swap_part = SSWAP16(1);
757
758         /* sizeof(sgilabel->boot_file) = 16 > 6 */
759         memset(sgilabel->boot_file, 0, 16);
760         strcpy((char *) sgilabel->boot_file, "/unix");
761
762         sgilabel->devparam.skew                 = (0);
763         sgilabel->devparam.gap1                 = (0);
764         sgilabel->devparam.gap2                 = (0);
765         sgilabel->devparam.sparecyl                     = (0);
766         sgilabel->devparam.pcylcount            = SSWAP16(geometry.cylinders);
767         sgilabel->devparam.head_vol0            = SSWAP16(0);
768         sgilabel->devparam.ntrks                        = SSWAP16(geometry.heads);
769         /* tracks/cylinder (heads) */
770         sgilabel->devparam.cmd_tag_queue_depth  = (0);
771         sgilabel->devparam.unused0                      = (0);
772         sgilabel->devparam.unused1                      = SSWAP16(0);
773         sgilabel->devparam.nsect                        = SSWAP16(geometry.sectors);
774         /* sectors/track */
775         sgilabel->devparam.bytes                        = SSWAP16(sector_size);
776         sgilabel->devparam.ilfact                       = SSWAP16(1);
777         sgilabel->devparam.flags                        = SSWAP32(TRACK_FWD|\
778                                                                   IGNORE_ERRORS|RESEEK);
779         sgilabel->devparam.datarate                     = SSWAP32(0);
780         sgilabel->devparam.retries_on_error             = SSWAP32(1);
781         sgilabel->devparam.ms_per_word          = SSWAP32(0);
782         sgilabel->devparam.xylogics_gap1                = SSWAP16(0);
783         sgilabel->devparam.xylogics_syncdelay   = SSWAP16(0);
784         sgilabel->devparam.xylogics_readdelay   = SSWAP16(0);
785         sgilabel->devparam.xylogics_gap2                = SSWAP16(0);
786         sgilabel->devparam.xylogics_readgate    = SSWAP16(0);
787         sgilabel->devparam.xylogics_writecont   = SSWAP16(0);
788         memset(&(sgilabel->directory), 0, sizeof(struct volume_directory)*15);
789         memset(&(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16);
790         sgi_label  =  1;
791         partitions = 16;
792         volumes    = 15;
793         sgi_set_entire();
794         sgi_set_volhdr();
795         for (i = 0; i < 4; i++) {
796                 if (old[i].sysid) {
797                         sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
798                 }
799         }
800 }
801
802 void
803 sgi_set_ilfact(void)
804 {
805         /* do nothing in the beginning */
806 }
807
808 void
809 sgi_set_rspeed(void)
810 {
811         /* do nothing in the beginning */
812 }
813
814 void
815 sgi_set_pcylcount(void)
816 {
817         /* do nothing in the beginning */
818 }
819
820 void
821 sgi_set_xcyl(void)
822 {
823         /* do nothing in the beginning */
824 }
825
826 void
827 sgi_set_ncyl(void)
828 {
829         /* do nothing in the beginning */
830 }
831
832 /* _____________________________________________________________
833  */
834
835 sgiinfo *
836 fill_sgiinfo(void)
837 {
838         sgiinfo*info=calloc(1, sizeof(sgiinfo));
839         info->magic=SSWAP32(SGI_INFO_MAGIC);
840         info->b1=SSWAP32(-1);
841         info->b2=SSWAP16(-1);
842         info->b3=SSWAP16(1);
843         /* You may want to replace this string !!!!!!! */
844         strcpy((char *) info->scsi_string, "IBM OEM 0662S12         3 30");
845         strcpy((char *) info->serial, "0000");
846         info->check1816 = SSWAP16(18*256 +16);
847         strcpy((char *) info->installer, "Sfx version 5.3, Oct 18, 1994");
848         return info;
849 }