enable login utils
[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 #include "xalloc.h"
26
27 #include "blkdev.h"
28
29 #include "common.h"
30 #include "fdisk.h"
31 #include "fdisksgilabel.h"
32
33 static  int     other_endian = 0;
34 static  int     debug = 0;
35 static  short volumes=1;
36
37 /*
38  * only dealing with free blocks here
39  */
40
41 typedef struct { unsigned int first; unsigned int last; } freeblocks;
42 static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
43
44 static void
45 setfreelist(int i, unsigned int f, unsigned int l) {
46         if (i < 17) {
47                 freelist[i].first = f;
48                 freelist[i].last = l;
49         }
50 }
51
52 static void
53 add2freelist(unsigned int f, unsigned int l) {
54         int i = 0;
55         for ( ; i < 17 ; i++)
56                 if (freelist[i].last == 0)
57                         break;
58         setfreelist(i, f, l);
59 }
60
61 static void
62 clearfreelist(void) {
63         int i;
64
65         for (i = 0; i < 17 ; i++)
66                 setfreelist(i, 0, 0);
67 }
68
69 static unsigned int
70 isinfreelist(unsigned int b) {
71         int i;
72
73         for (i = 0; i < 17 ; i++)
74                 if (freelist[i].first <= b && freelist[i].last >= b)
75                         return freelist[i].last;
76         return 0;
77 }
78         /* return last vacant block of this stride (never 0). */
79         /* the '>=' is not quite correct, but simplifies the code */
80 /*
81  * end of free blocks section
82  */
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")},
102         {0, NULL }
103 };
104
105 static int
106 sgi_get_nsect(void) {
107         return SSWAP16(sgilabel->devparam.nsect);
108 }
109
110 static int
111 sgi_get_ntrks(void) {
112         return SSWAP16(sgilabel->devparam.ntrks);
113 }
114
115 #if 0
116 static int
117 sgi_get_head_vol0(void) {
118         return SSWAP16(sgilabel->devparam.head_vol0);
119 }
120
121 static int
122 sgi_get_bytes(void) {
123         return SSWAP16(sgilabel->devparam.bytes);
124 }
125
126 static int
127 sgi_get_pcylcount(void) {
128         return SSWAP16(sgilabel->devparam.pcylcount);
129 }
130 #endif
131
132 void
133 sgi_nolabel() {
134         sgilabel->magic = 0;
135         partitions = 4;
136 }
137
138 static unsigned int
139 two_s_complement_32bit_sum(unsigned int *base, int size /* in bytes */) {
140         int i = 0;
141         unsigned int sum = 0;
142
143         size /= sizeof(unsigned int);
144         for (i = 0; i < size; i++)
145                 sum -= SSWAP32(base[i]);
146         return sum;
147 }
148
149 int
150 check_sgi_label() {
151         if (sizeof(sgilabel) > 512) {
152                 fprintf(stderr,
153                         _("According to MIPS Computer Systems, Inc the "
154                           "Label must not contain more than 512 bytes\n"));
155                 exit(1);
156         }
157
158         if (sgilabel->magic != SGI_LABEL_MAGIC &&
159             sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
160                 other_endian = 0;
161                 return 0;
162         }
163
164         other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
165         /*
166          * test for correct checksum
167          */
168         if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
169                                        sizeof(*sgilabel))) {
170                 fprintf(stderr,
171                         _("Detected sgi disklabel with wrong checksum.\n"));
172         }
173         update_units();
174         disklabel = SGI_LABEL;
175         partitions= 16;
176         volumes = 15;
177         return 1;
178 }
179
180 void
181 sgi_list_table(int xtra) {
182         int i, w;
183         int kpi = 0;            /* kernel partition ID */
184         char *type;
185
186         w = strlen(disk_device);
187
188         if (xtra) {
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"
192                          "%s\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),
198                        (char *)sgilabel,
199                        str_units(PLURAL), units_per_sector,
200                        sector_size);
201         } else {
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,
207                        sector_size);
208         }
209         printf(_("----- partitions -----\n"
210                  "Pt# %*s  Info     Start       End   Sectors  Id  System\n"),
211                w + 1, _("Device"));
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 */
217                         printf(
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"));
229                 }
230         }
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,
241                                (unsigned int) len);
242                 }
243         }
244 }
245
246 unsigned int
247 sgi_get_start_sector(int i) {
248         return SSWAP32(sgilabel->partitions[i].start_sector);
249 }
250
251 unsigned int
252 sgi_get_num_sectors(int i) {
253         return SSWAP32(sgilabel->partitions[i].num_sectors);
254 }
255
256 int
257 sgi_get_sysid(int i)
258 {
259         return SSWAP32(sgilabel->partitions[i].id);
260 }
261
262 int
263 sgi_get_bootpartition(void)
264 {
265         return SSWAP16(sgilabel->boot_part);
266 }
267
268 int
269 sgi_get_swappartition(void)
270 {
271         return SSWAP16(sgilabel->swap_part);
272 }
273
274 void
275 sgi_set_bootpartition(int i)
276 {
277         sgilabel->boot_part = SSWAP16(((short)i));
278 }
279
280 static unsigned int
281 sgi_get_lastblock(void) {
282         return heads * sectors * cylinders;
283 }
284
285 void
286 sgi_set_swappartition(int i) {
287         sgilabel->swap_part = SSWAP16(((short)i));
288 }
289
290 static int
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"));
296                 return 0;
297         } else {
298                 if (strlen(aFile) > 16) {
299                         printf(_("\n\tName of Bootfile too long:  "
300                                  "16 bytes maximum.\n"));
301                         return 0;
302                 } else {
303                         if (aFile[0] != '/') {
304                                 printf(_("\n\tBootfile must have a "
305                                          "fully qualified pathname.\n"));
306                                 return 0;
307                         }
308                 }
309         }
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 */
314                 return 1;
315         }
316         return 0;       /* filename did not change */
317 }
318
319 const char *
320 sgi_get_bootfile(void) {
321         return (char *) sgilabel->boot_file;
322 }
323
324 void
325 sgi_set_bootfile(const char* aFile) {
326
327         if (sgi_check_bootfile(aFile)) {
328                 size_t i = 0;
329                 while (i < 16) {
330                         if ((aFile[i] != '\n')  /* in principle caught again by next line */
331                             &&  (strlen(aFile) > i))
332                                 sgilabel->boot_file[i] = aFile[i];
333                         else
334                                 sgilabel->boot_file[i] = 0;
335                         i++;
336                 }
337                 printf(_("\n\tBootfile is changed to \"%s\".\n"),
338                        sgilabel->boot_file);
339         }
340 }
341
342 void
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);
348 }
349
350 sgiinfo *fill_sgiinfo(void);
351
352 void
353 sgi_write_table(void) {
354         sgilabel->csum = 0;
355         sgilabel->csum = SSWAP32(two_s_complement_32bit_sum(
356                 (unsigned int*)sgilabel, 
357                 sizeof(*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)) {
365                 /*
366                  * keep this habit of first writing the "sgilabel".
367                  * I never tested whether it works without (AN 981002).
368                  */
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);
376                 free(info);
377         }
378 }
379
380 static int
381 compare_start(int *x, int *y) {
382         /*
383          * sort according to start sectors
384          * and prefers largest partition:
385          * entry zero is entire disk entry
386          */
387         unsigned int i = *x;
388         unsigned int j = *y;
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);
393
394         if (a == b)
395                 return (d > c) ? 1 : (d == c) ? 0 : -1;
396         return (a > b) ? 1 : -1;
397 }
398
399 static int
400 sgi_gaps(void) {
401         /*
402          * returned value is:
403          *  = 0 : disk is properly filled to the rim
404          *  < 0 : there is an overlap
405          *  > 0 : there is still some vacant space
406          */
407         return verify_sgi(0);
408 }
409
410 int
411 verify_sgi(int verbose)
412 {
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();
419
420         clearfreelist();
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) {
425                                 if (entire++ == 1) {
426                                         if (verbose)
427                                                 printf(_("More than one entire disk entry present.\n"));
428                                 }
429                         }
430                 }
431         }
432         if (sortcount == 0) {
433                 if (verbose)
434                         printf(_("No partitions defined\n"));
435                 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
436         }
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 "
443                                  "at block 0,\n"
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]);
452         } else {
453                 if (verbose)
454                         printf(_("One Partition (#11) should cover the entire disk.\n"));
455                 if (debug>2)
456                         printf("sysid=%d\tpartition=%d\n",
457                                sgi_get_sysid(Index[0]), Index[0]+1);
458         }
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 */
463                                 if (verbose)
464                                         printf(_("Partition %d does not start on cylinder boundary.\n"),
465                                                Index[i]+1);
466                 }
467                 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
468                         if (debug)      /* I do not understand how some disks fulfil it */
469                                 if (verbose)
470                                         printf(_("Partition %d does not end on cylinder boundary.\n"),
471                                                Index[i]+1);
472                 }
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])) {
476                         if (verbose)
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;
482                 }
483                 if (start < sgi_get_start_sector(Index[i])) {
484                         if (verbose)
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]));
490                 }
491                 start = sgi_get_start_sector(Index[i])
492                         + sgi_get_num_sectors(Index[i]);
493                 /* Align free space on cylinder boundary */
494                 if (start % cylsize)
495                         start += cylsize - (start % cylsize);
496                 if (debug > 1) {
497                         if (verbose)
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]));
502                 }
503         }
504         if (start < lastblock) {
505                 if (verbose)
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);
510         }
511         /*
512          * Done with arithmetics
513          * Go for details now
514          */
515         if (verbose) {
516                 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
517                         printf(_("\nThe boot partition does not exist.\n"));
518                 }
519                 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
520                         printf(_("\nThe swap partition does not exist.\n"));
521                 } else {
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"));
525                 }
526                 if (sgi_check_bootfile("/unix"))
527                         printf(_("\tYou have chosen an unusual boot file name.\n"));
528         }
529         return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
530 }
531
532 int
533 sgi_change_sysid(int i, int sys)
534 {
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"));
537                 return 0;
538         }
539         if (((sys != ENTIRE_DISK) && (sys != SGI_VOLHDR))
540             && (sgi_get_start_sector(i)<1)) {
541                 read_chars(
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")))
548                         return 0;
549         }
550         sgilabel->partitions[i].id = SSWAP32(sys);
551         return 1;
552 }
553
554 /* returns partition index of first entry marked as entire disk */
555 static int
556 sgi_entire(void) {
557         int i;
558
559         for (i=0; i<16; i++)
560                 if (sgi_get_sysid(i) == SGI_VOLUME)
561                         return i;
562         return -1;
563 }
564
565 static void
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);
570         set_changed(i);
571         if (sgi_gaps() < 0)     /* rebuild freelist */
572                 printf(_("Do You know, You got a partition overlap on the disk?\n"));
573 }
574
575 static void
576 sgi_set_entire(void) {
577         int n;
578
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);
582                         break;
583                 }
584         }
585 }
586
587 static
588 void
589 sgi_set_volhdr(void)
590 {
591         int n;
592
593         for (n=8; n<partitions; n++) {
594                 if (!sgi_get_num_sectors(n)) {
595                         /*
596                          * Choose same default volume header size
597                          * as IRIX fx uses.
598                          */
599                         if (4096 < sgi_get_lastblock())
600                                 sgi_set_partition(n, 0, 4096, SGI_VOLHDR);
601                         break;
602                 }
603         }
604 }
605
606 void
607 sgi_delete_partition(int i)
608 {
609         sgi_set_partition(i, 0, 0, 0);
610 }
611
612 void
613 sgi_add_partition(int n, int sys)
614 {
615         char mesg[256];
616         unsigned int first=0, last=0;
617
618         if (n == 10) {
619                 sys = SGI_VOLUME;
620         } else if (n == 8) {
621                 sys = 0;
622         }
623         if (sgi_get_num_sectors(n)) {
624                 printf(_("Partition %d is already defined.  Delete "
625                          "it before re-adding it.\n"), n + 1);
626                 return;
627         }
628         if ((sgi_entire() == -1)
629             &&  (sys != SGI_VOLUME)) {
630                 printf(_("Attempting to generate entire disk entry automatically.\n"));
631                 sgi_set_entire();
632                 sgi_set_volhdr();
633         }
634         if ((sgi_gaps() == 0) &&  (sys != SGI_VOLUME)) {
635                 printf(_("The entire disk is already covered with partitions.\n"));
636                 return;
637         }
638         if (sgi_gaps() < 0) {
639                 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
640                 return;
641         }
642         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
643         for (;;) {
644                 if (sys == SGI_VOLUME) {
645                         last = sgi_get_lastblock();
646                         first = read_int(0, 0, last-1, 0, mesg);
647                         if (first != 0) {
648                                 printf(_("It is highly recommended that eleventh partition\n"
649                                          "covers the entire disk and is of type `SGI volume'\n"));
650                         }
651                 } else {
652                         first = freelist[0].first;
653                         last  = freelist[0].last;
654                         first = read_int(scround(first), scround(first), scround(last)-1,
655                                          0, mesg);
656                 }
657                 if (display_in_cyl_units)
658                         first *= units_per_sector;
659                 else
660                         first = first; /* align to cylinder if you know how ... */
661                 if (!last)
662                         last = isinfreelist(first);
663                 if (last == 0) {
664                         printf(_("You will get a partition overlap on the disk. "
665                                  "Fix it first!\n"));
666                 } else
667                         break;
668         }
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;                                     
674         else                                                             
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);
680 }
681
682 void
683 create_sgilabel(void)
684 {
685         struct hd_geometry geometry;
686         struct {
687                 unsigned int start;
688                 unsigned int nsect;
689                 int sysid;
690         } old[4];
691         int i=0;
692         unsigned long long llsectors;
693         int res;                /* the result from the ioctl */
694         int sec_fac;            /* the sector factor */
695
696         sec_fac = sector_size / 512;    /* determine the sector factor */
697
698         fprintf(stderr,
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"));
702
703         other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
704
705         res = blkdev_get_sectors(fd, &llsectors);
706
707 #ifdef HDIO_GETGEO
708         if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
709                 heads = geometry.heads;
710                 sectors = geometry.sectors;
711                 if (res == 0) {
712                         /* the get device size ioctl was successful */
713                         unsigned long long llcyls;
714                         llcyls = llsectors / (heads * sectors * sec_fac);
715                         cylinders = llcyls;
716                         if (cylinders != llcyls)        /* truncated? */
717                                 cylinders = ~0;
718                 } else {
719                         /* otherwise print error and use truncated version */
720                         cylinders = geometry.cylinders;
721                         fprintf(stderr,
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);
726                 }
727         }
728 #endif
729         for (i = 0; i < 4; i++) {
730                 old[i].sysid = 0;
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);
737                                 if (debug)
738                                         printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
739                                                old[i].sysid, old[i].start, old[i].nsect);
740                         }
741                 }
742         }
743
744         zeroize_mbr_buffer();
745         sgilabel->magic = SSWAP32(SGI_LABEL_MAGIC);
746         sgilabel->boot_part = SSWAP16(0);
747         sgilabel->swap_part = SSWAP16(1);
748
749         /* sizeof(sgilabel->boot_file) = 16 > 6 */
750         memset(sgilabel->boot_file, 0, 16);
751         strcpy((char *) sgilabel->boot_file, "/unix");
752
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);
765         /* sectors/track */
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;
782         partitions = 16;
783         volumes    = 15;
784         sgi_set_entire();
785         sgi_set_volhdr();
786         for (i = 0; i < 4; i++) {
787                 if (old[i].sysid) {
788                         sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
789                 }
790         }
791 }
792
793 void
794 sgi_set_ilfact(void)
795 {
796         /* do nothing in the beginning */
797 }
798
799 void
800 sgi_set_rspeed(void)
801 {
802         /* do nothing in the beginning */
803 }
804
805 void
806 sgi_set_pcylcount(void)
807 {
808         /* do nothing in the beginning */
809 }
810
811 void
812 sgi_set_xcyl(void)
813 {
814         /* do nothing in the beginning */
815 }
816
817 void
818 sgi_set_ncyl(void)
819 {
820         /* do nothing in the beginning */
821 }
822
823 /* _____________________________________________________________
824  */
825
826 sgiinfo *
827 fill_sgiinfo(void)
828 {
829         sgiinfo *info=xcalloc(1, sizeof(sgiinfo));
830         info->magic=SSWAP32(SGI_INFO_MAGIC);
831         info->b1=SSWAP32(-1);
832         info->b2=SSWAP16(-1);
833         info->b3=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");
839         return info;
840 }