blob: 1fce0c1c7b4ebef7f3c009dc11be1965efb75c2e [file] [log] [blame]
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00001#if ENABLE_FEATURE_SGI_LABEL
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00003#define SGI_DEBUG 0
4
Denis Vlasenko98ae2162006-10-12 19:30:44 +00005/*
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
Denis Vlasenkobd852072007-03-19 14:43:38 +000011#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
Denis Vlasenko98ae2162006-10-12 19:30:44 +000025struct 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
62typedef 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
82typedef 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
Denis Vlasenko28703012006-12-19 20:32:02 +0000103#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))
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000105
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
Denis Vlasenko284d0fa2008-02-16 13:18:17 +0000122static smallint sgi_other_endian; /* bool */
123static smallint sgi_volumes = 1; /* max 15 */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000124
125/*
126 * only dealing with free blocks here
127 */
128
129typedef struct {
130 unsigned int first;
131 unsigned int last;
132} freeblocks;
133static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
134
135static void
136setfreelist(int i, unsigned int f, unsigned int l)
137{
138 freelist[i].first = f;
139 freelist[i].last = l;
140}
141
142static void
143add2freelist(unsigned int f, unsigned int l)
144{
145 int i;
Denis Vlasenkob71c6682007-07-21 15:08:09 +0000146 for (i = 0; i < 17; i++)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000147 if (freelist[i].last == 0)
148 break;
149 setfreelist(i, f, l);
150}
151
152static void
153clearfreelist(void)
154{
155 int i;
156
Denis Vlasenkob71c6682007-07-21 15:08:09 +0000157 for (i = 0; i < 17; i++)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000158 setfreelist(i, 0, 0);
159}
160
161static unsigned int
162isinfreelist(unsigned int b)
163{
164 int i;
165
Denis Vlasenkob71c6682007-07-21 15:08:09 +0000166 for (i = 0; i < 17; i++)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000167 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
Denis Vlasenkobd852072007-03-19 14:43:38 +0000177static 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
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000197};
198
199
200static int
201sgi_get_nsect(void)
202{
203 return SGI_SSWAP16(sgilabel->devparam.nsect);
204}
205
206static int
207sgi_get_ntrks(void)
208{
209 return SGI_SSWAP16(sgilabel->devparam.ntrks);
210}
211
212static unsigned int
213two_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
Denis Vlasenkobd852072007-03-19 14:43:38 +0000224void BUG_bad_sgi_partition_size(void);
225
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000226static int
227check_sgi_label(void)
228{
Denis Vlasenkobd852072007-03-19 14:43:38 +0000229 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();
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000233 }
234
235 if (sgilabel->magic != SGI_LABEL_MAGIC
Denis Vlasenkobd852072007-03-19 14:43:38 +0000236 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED
237 ) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000238 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))) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000248 printf("Detected sgi disklabel with wrong checksum\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000249 }
250 update_units();
251 current_label_type = label_sgi;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000252 g_partitions = 16;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000253 sgi_volumes = 15;
254 return 1;
255}
256
257static unsigned int
258sgi_get_start_sector(int i)
259{
260 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
261}
262
263static unsigned int
264sgi_get_num_sectors(int i)
265{
266 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
267}
268
269static int
270sgi_get_sysid(int i)
271{
272 return SGI_SSWAP32(sgilabel->partitions[i].id);
273}
274
275static int
276sgi_get_bootpartition(void)
277{
278 return SGI_SSWAP16(sgilabel->boot_part);
279}
280
281static int
282sgi_get_swappartition(void)
283{
284 return SGI_SSWAP16(sgilabel->swap_part);
285}
286
287static void
288sgi_list_table(int xtra)
289{
290 int i, w, wd;
291 int kpi = 0; /* kernel partition ID */
292
Denis Vlasenkobd852072007-03-19 14:43:38 +0000293 if (xtra) {
294 printf("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000295 "%d cylinders, %d physical cylinders\n"
296 "%d extra sects/cyl, interleave %d:1\n"
297 "%s\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000298 "Units = %s of %d * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000299 disk_device, g_heads, g_sectors, g_cylinders,
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000300 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 {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000306 printf("\nDisk %s (SGI disk label): "
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000307 "%d heads, %d sectors, %d cylinders\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000308 "Units = %s of %d * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000309 disk_device, g_heads, g_sectors, g_cylinders,
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000310 str_units(PLURAL), units_per_sector );
311 }
312
313 w = strlen(disk_device);
Denis Vlasenkobd852072007-03-19 14:43:38 +0000314 wd = sizeof("Device") - 1;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000315 if (w < wd)
316 w = wd;
317
Denis Vlasenkobd852072007-03-19 14:43:38 +0000318 printf("----- partitions -----\n"
319 "Pt# %*s Info Start End Sectors Id System\n",
320 w + 2, "Device");
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000321 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko284d0fa2008-02-16 13:18:17 +0000322 if (sgi_get_num_sectors(i) || SGI_DEBUG) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000323 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 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000339 printf("----- Bootinfo -----\nBootfile: %s\n"
340 "----- Directory Entries -----\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000341 sgilabel->boot_file);
Denis Vlasenkob71c6682007-07-21 15:08:09 +0000342 for (i = 0; i < sgi_volumes; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000343 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
Denis Vlasenkobd852072007-03-19 14:43:38 +0000348 printf("%2d: %-10s sector%5u size%8u\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000349 i, (char*)name, (unsigned int) start, (unsigned int) len);
350 }
351 }
352}
353
354static void
355sgi_set_bootpartition(int i)
356{
357 sgilabel->boot_part = SGI_SSWAP16(((short)i));
358}
359
360static unsigned int
361sgi_get_lastblock(void)
362{
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000363 return g_heads * g_sectors * g_cylinders;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000364}
365
366static void
367sgi_set_swappartition(int i)
368{
369 sgilabel->swap_part = SGI_SSWAP16(((short)i));
370}
371
372static int
373sgi_check_bootfile(const char* aFile)
374{
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000375 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000376 printf("\nInvalid Bootfile!\n"
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000377 "\tThe bootfile must be an absolute non-zero pathname,\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000378 "\te.g. \"/unix\" or \"/unix.save\".\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000379 return 0;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000380 }
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 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000389 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000390 printf("\nBe aware, that the bootfile is not checked for existence.\n"
391 "\tSGI's default is \"/unix\" and for backup \"/unix.save\".\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000392 /* filename is correct and did change */
393 return 1;
394 }
395 return 0; /* filename did not change */
396}
397
398static const char *
399sgi_get_bootfile(void)
400{
401 return (char*)sgilabel->boot_file;
402}
403
404static void
405sgi_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 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000418 printf("\n\tBootfile is changed to \"%s\"\n", sgilabel->boot_file);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000419 }
420}
421
422static void
423create_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
431static sgiinfo *fill_sgiinfo(void);
432
433static void
434sgi_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
461static int
462compare_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
482static int
483verify_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)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000499 printf("More than one entire disk entry present\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000500 }
501 }
502 }
503 }
504 if (sortcount == 0) {
505 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000506 printf("No partitions defined\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000507 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)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000512 printf("IRIX likes when Partition 11 covers the entire disk\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000513 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000514 printf("The entire disk partition should start "
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000515 "at block 0,\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000516 "not at diskblock %d\n",
517 sgi_get_start_sector(Index[0]));
Denis Vlasenko284d0fa2008-02-16 13:18:17 +0000518 if (SGI_DEBUG) /* I do not understand how some disks fulfil it */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000519 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000520 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]);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000524 } else {
525 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000526 printf("One Partition (#11) should cover the entire disk\n");
Denis Vlasenko284d0fa2008-02-16 13:18:17 +0000527 if (SGI_DEBUG > 2)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000528 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) {
Denis Vlasenko284d0fa2008-02-16 13:18:17 +0000535 if (SGI_DEBUG) /* I do not understand how some disks fulfil it */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000536 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000537 printf("Partition %d does not start on cylinder boundary\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000538 Index[i]+1);
539 }
540 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
Denis Vlasenko284d0fa2008-02-16 13:18:17 +0000541 if (SGI_DEBUG) /* I do not understand how some disks fulfil it */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000542 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000543 printf("Partition %d does not end on cylinder boundary\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000544 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)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000550 printf("Partitions %d and %d overlap by %d sectors\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000551 Index[i-1]+1, Index[i]+1,
552 start - sgi_get_start_sector(Index[i]));
Denis Vlasenkobd852072007-03-19 14:43:38 +0000553 if (gap > 0) gap = -gap;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000554 if (gap == 0) gap = -1;
555 }
556 if (start < sgi_get_start_sector(Index[i])) {
557 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000558 printf("Unused gap of %8u sectors - sectors %8u-%8u\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000559 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]);
Denis Vlasenko284d0fa2008-02-16 13:18:17 +0000566 if (SGI_DEBUG > 1) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000567 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)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000576 printf("Unused gap of %8u sectors - sectors %8u-%8u\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000577 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())) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000587 printf("\nThe boot partition does not exist\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000588 }
589 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000590 printf("\nThe swap partition does not exist\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000591 } else {
592 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
593 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
Denis Vlasenkobd852072007-03-19 14:43:38 +0000594 printf("\nThe swap partition has no swap type\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000595 }
596 if (sgi_check_bootfile("/unix"))
Denis Vlasenkobd852072007-03-19 14:43:38 +0000597 printf("\tYou have chosen an unusual boot file name\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000598 }
599 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
600}
601
602static int
603sgi_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
614static void
615sgi_change_sysid(int i, int sys)
616{
Denis Vlasenko219d14d2007-03-24 15:40:16 +0000617 if (sgi_get_num_sectors(i) == 0) { /* caught already before, ... */
Denis Vlasenkobd852072007-03-19 14:43:38 +0000618 printf("Sorry you may change the Tag of non-empty partitions\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000619 return;
620 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000621 if ((sys != SGI_ENTIRE_DISK) && (sys != SGI_VOLHDR)
622 && (sgi_get_start_sector(i) < 1)
623 ) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000624 read_maybe_empty(
Denis Vlasenkobd852072007-03-19 14:43:38 +0000625 "It is highly recommended that the partition at offset 0\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000626 "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"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000629 "Type YES if you are sure about tagging this partition differently.\n");
630 if (strcmp(line_ptr, "YES\n") != 0)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000631 return;
632 }
633 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
634}
635
636/* returns partition index of first entry marked as entire disk */
637static int
638sgi_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
648static void
649sgi_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 */
Denis Vlasenkobd852072007-03-19 14:43:38 +0000656 printf("Partition overlap detected\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000657}
658
659static void
660sgi_set_entire(void)
661{
662 int n;
663
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000664 for (n = 10; n < g_partitions; n++) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000665 if (!sgi_get_num_sectors(n) ) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000666 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
667 break;
668 }
669 }
670}
671
672static void
673sgi_set_volhdr(void)
674{
675 int n;
676
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000677 for (n = 8; n < g_partitions; n++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000678 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 */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000685 if (g_heads * g_sectors * 5 < sgi_get_lastblock())
686 sgi_set_partition(n, 0, g_heads * g_sectors * 5, SGI_VOLHDR);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000687 break;
688 }
689 }
690}
691
692static void
693sgi_delete_partition(int i)
694{
695 sgi_set_partition(i, 0, 0, 0);
696}
697
698static void
699sgi_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 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000709 if (sgi_get_num_sectors(n)) {
710 printf(msg_part_already_defined, n + 1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000711 return;
712 }
713 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000714 printf("Attempting to generate entire disk entry automatically\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000715 sgi_set_entire();
716 sgi_set_volhdr();
717 }
718 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000719 printf("The entire disk is already covered with partitions\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000720 return;
721 }
722 if (sgi_gaps() < 0) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000723 printf("You got a partition overlap on the disk. Fix it first!\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000724 return;
725 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000726 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000727 while (1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000728 if (sys == SGI_VOLUME) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000729 last = sgi_get_lastblock();
730 first = read_int(0, 0, last-1, 0, mesg);
731 if (first != 0) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000732 printf("It is highly recommended that eleventh partition\n"
733 "covers the entire disk and is of type 'SGI volume'\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000734 }
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 ... */
Denis Vlasenkobd852072007-03-19 14:43:38 +0000745 if (!last )
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000746 last = isinfreelist(first);
Denis Vlasenkobd852072007-03-19 14:43:38 +0000747 if (last != 0)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000748 break;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000749 printf("You will get a partition overlap on the disk. "
750 "Fix it first!\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000751 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000752 snprintf(mesg, sizeof(mesg), " Last %s", str_units(SINGULAR));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000753 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() ) )
Denis Vlasenkobd852072007-03-19 14:43:38 +0000760 printf("It is highly recommended that eleventh partition\n"
761 "covers the entire disk and is of type 'SGI volume'\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000762 sgi_set_partition(n, first, last-first, sys);
763}
764
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000765#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000766static void
767create_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
Denis Vlasenkobd852072007-03-19 14:43:38 +0000782 printf(msg_building_new_label, "SGI disklabel");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000783
Denis Vlasenkode7684a2008-02-18 21:08:49 +0000784 sgi_other_endian = BB_LITTLE_ENDIAN;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000785 res = ioctl(fd, BLKGETSIZE, &longsectors);
786 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000787 g_heads = geometry.heads;
788 g_sectors = geometry.sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000789 if (res == 0) {
790 /* the get device size ioctl was successful */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000791 g_cylinders = longsectors / (g_heads * g_sectors);
792 g_cylinders /= sec_fac;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000793 } else {
794 /* otherwise print error and use truncated version */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000795 g_cylinders = geometry.cylinders;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000796 printf(
797"Warning: BLKGETSIZE ioctl failed on %s. Using geometry cylinder value of %d.\n"
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000798"This value may be truncated for devices > 33.8 GB.\n", disk_device, g_cylinders);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000799 }
800 }
801 for (i = 0; i < 4; i++) {
802 old[i].sysid = 0;
803 if (valid_part_table_flag(MBRbuffer)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000804 if (get_part_table(i)->sys_ind) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000805 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));
Denis Vlasenkobd852072007-03-19 14:43:38 +0000808 printf("Trying to keep parameters of partition %d\n", i);
Denis Vlasenko284d0fa2008-02-16 13:18:17 +0000809 if (SGI_DEBUG)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000810 printf("ID=%02x\tSTART=%d\tLENGTH=%d\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000811 old[i].sysid, old[i].start, old[i].nsect);
812 }
813 }
814 }
815
816 memset(MBRbuffer, 0, sizeof(MBRbuffer));
Denis Vlasenkod5470832007-01-03 02:58:54 +0000817 /* fields with '//' are already zeroed out by memset above */
818
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000819 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
Denis Vlasenkod5470832007-01-03 02:58:54 +0000820 //sgilabel->boot_part = SGI_SSWAP16(0);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000821 sgilabel->swap_part = SGI_SSWAP16(1);
822
Denis Vlasenkod5470832007-01-03 02:58:54 +0000823 //memset(sgilabel->boot_file, 0, 16);
824 strcpy((char*)sgilabel->boot_file, "/unix"); /* sizeof(sgilabel->boot_file) == 16 > 6 */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000825
Denis Vlasenkod5470832007-01-03 02:58:54 +0000826 //sgilabel->devparam.skew = (0);
827 //sgilabel->devparam.gap1 = (0);
828 //sgilabel->devparam.gap2 = (0);
829 //sgilabel->devparam.sparecyl = (0);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000830 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
Denis Vlasenkod5470832007-01-03 02:58:54 +0000831 //sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
832 /* tracks/cylinder (heads) */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000833 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Denis Vlasenkod5470832007-01-03 02:58:54 +0000834 //sgilabel->devparam.cmd_tag_queue_depth = (0);
835 //sgilabel->devparam.unused0 = (0);
836 //sgilabel->devparam.unused1 = SGI_SSWAP16(0);
837 /* sectors/track */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000838 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000839 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);
Denis Vlasenkod5470832007-01-03 02:58:54 +0000843 //sgilabel->devparam.datarate = SGI_SSWAP32(0);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000844 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
Denis Vlasenkod5470832007-01-03 02:58:54 +0000845 //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 );
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000854 current_label_type = label_sgi;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000855 g_partitions = 16;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000856 sgi_volumes = 15;
857 sgi_set_entire();
858 sgi_set_volhdr();
859 for (i = 0; i < 4; i++) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000860 if (old[i].sysid) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000861 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
862 }
863 }
864}
865
866static void
867sgi_set_xcyl(void)
868{
869 /* do nothing in the beginning */
870}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000871#endif /* FEATURE_FDISK_ADVANCED */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000872
873/* _____________________________________________________________
874 */
875
876static sgiinfo *
877fill_sgiinfo(void)
878{
Denis Vlasenko9b1381f2007-01-03 02:56:00 +0000879 sgiinfo *info = xzalloc(sizeof(sgiinfo));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000880
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 */