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