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