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