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