blob: f0bd195a15dec1cf9d9f7948896d1bd3242e77e0 [file] [log] [blame]
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00001#if ENABLE_FEATURE_SGI_LABEL
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002
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
Denis Vlasenkobd852072007-03-19 14:43:38 +00009#define SGI_VOLHDR 0x00
10/* 1 and 2 were used for drive types no longer supported by SGI */
11#define SGI_SWAP 0x03
12/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
13#define SGI_VOLUME 0x06
14#define SGI_EFS 0x07
15#define SGI_LVOL 0x08
16#define SGI_RLVOL 0x09
17#define SGI_XFS 0x0a
18#define SGI_XFSLOG 0x0b
19#define SGI_XLV 0x0c
20#define SGI_XVM 0x0d
21#define SGI_ENTIRE_DISK SGI_VOLUME
22
Denis Vlasenko98ae2162006-10-12 19:30:44 +000023struct device_parameter { /* 48 bytes */
24 unsigned char skew;
25 unsigned char gap1;
26 unsigned char gap2;
27 unsigned char sparecyl;
28 unsigned short pcylcount;
29 unsigned short head_vol0;
30 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
31 unsigned char cmd_tag_queue_depth;
32 unsigned char unused0;
33 unsigned short unused1;
34 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
35 unsigned short bytes;
36 unsigned short ilfact;
37 unsigned int flags; /* controller flags */
38 unsigned int datarate;
39 unsigned int retries_on_error;
40 unsigned int ms_per_word;
41 unsigned short xylogics_gap1;
42 unsigned short xylogics_syncdelay;
43 unsigned short xylogics_readdelay;
44 unsigned short xylogics_gap2;
45 unsigned short xylogics_readgate;
46 unsigned short xylogics_writecont;
47};
48
49/*
50 * controller flags
51 */
52#define SECTOR_SLIP 0x01
53#define SECTOR_FWD 0x02
54#define TRACK_FWD 0x04
55#define TRACK_MULTIVOL 0x08
56#define IGNORE_ERRORS 0x10
57#define RESEEK 0x20
58#define ENABLE_CMDTAGQ 0x40
59
60typedef struct {
61 unsigned int magic; /* expect SGI_LABEL_MAGIC */
62 unsigned short boot_part; /* active boot partition */
63 unsigned short swap_part; /* active swap partition */
64 unsigned char boot_file[16]; /* name of the bootfile */
65 struct device_parameter devparam; /* 1 * 48 bytes */
66 struct volume_directory { /* 15 * 16 bytes */
67 unsigned char vol_file_name[8]; /* a character array */
68 unsigned int vol_file_start; /* number of logical block */
69 unsigned int vol_file_size; /* number of bytes */
70 } directory[15];
71 struct sgi_partinfo { /* 16 * 12 bytes */
72 unsigned int num_sectors; /* number of blocks */
73 unsigned int start_sector; /* must be cylinder aligned */
74 unsigned int id;
75 } partitions[16];
76 unsigned int csum;
77 unsigned int fillbytes;
78} sgi_partition;
79
80typedef struct {
81 unsigned int magic; /* looks like a magic number */
82 unsigned int a2;
83 unsigned int a3;
84 unsigned int a4;
85 unsigned int b1;
86 unsigned short b2;
87 unsigned short b3;
88 unsigned int c[16];
89 unsigned short d[3];
90 unsigned char scsi_string[50];
91 unsigned char serial[137];
92 unsigned short check1816;
93 unsigned char installer[225];
94} sgiinfo;
95
96#define SGI_LABEL_MAGIC 0x0be5a941
97#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
98#define SGI_INFO_MAGIC 0x00072959
99#define SGI_INFO_MAGIC_SWAPPED 0x59290700
100
Denis Vlasenko28703012006-12-19 20:32:02 +0000101#define SGI_SSWAP16(x) (sgi_other_endian ? fdisk_swap16(x) : (uint16_t)(x))
102#define SGI_SSWAP32(x) (sgi_other_endian ? fdisk_swap32(x) : (uint32_t)(x))
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000103
104#define sgilabel ((sgi_partition *)MBRbuffer)
105#define sgiparam (sgilabel->devparam)
106
107/*
108 *
109 * fdisksgilabel.c
110 *
111 * Copyright (C) Andreas Neuper, Sep 1998.
112 * This file may be modified and redistributed under
113 * the terms of the GNU Public License.
114 *
115 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
116 * Internationalization
117 */
118
119
120static int sgi_other_endian;
121static int debug;
122static short sgi_volumes = 1;
123
124/*
125 * only dealing with free blocks here
126 */
127
128typedef struct {
129 unsigned int first;
130 unsigned int last;
131} freeblocks;
132static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
133
134static void
135setfreelist(int i, unsigned int f, unsigned int l)
136{
137 freelist[i].first = f;
138 freelist[i].last = l;
139}
140
141static void
142add2freelist(unsigned int f, unsigned int l)
143{
144 int i;
Denis Vlasenkob71c6682007-07-21 15:08:09 +0000145 for (i = 0; i < 17; i++)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000146 if (freelist[i].last == 0)
147 break;
148 setfreelist(i, f, l);
149}
150
151static void
152clearfreelist(void)
153{
154 int i;
155
Denis Vlasenkob71c6682007-07-21 15:08:09 +0000156 for (i = 0; i < 17; i++)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000157 setfreelist(i, 0, 0);
158}
159
160static unsigned int
161isinfreelist(unsigned int b)
162{
163 int i;
164
Denis Vlasenkob71c6682007-07-21 15:08:09 +0000165 for (i = 0; i < 17; i++)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000166 if (freelist[i].first <= b && freelist[i].last >= b)
167 return freelist[i].last;
168 return 0;
169}
170 /* return last vacant block of this stride (never 0). */
171 /* the '>=' is not quite correct, but simplifies the code */
172/*
173 * end of free blocks section
174 */
175
Denis Vlasenkobd852072007-03-19 14:43:38 +0000176static const char *const sgi_sys_types[] = {
177/* SGI_VOLHDR */ "\x00" "SGI volhdr" ,
178/* 0x01 */ "\x01" "SGI trkrepl" ,
179/* 0x02 */ "\x02" "SGI secrepl" ,
180/* SGI_SWAP */ "\x03" "SGI raw" ,
181/* 0x04 */ "\x04" "SGI bsd" ,
182/* 0x05 */ "\x05" "SGI sysv" ,
183/* SGI_ENTIRE_DISK */ "\x06" "SGI volume" ,
184/* SGI_EFS */ "\x07" "SGI efs" ,
185/* 0x08 */ "\x08" "SGI lvol" ,
186/* 0x09 */ "\x09" "SGI rlvol" ,
187/* SGI_XFS */ "\x0a" "SGI xfs" ,
188/* SGI_XFSLOG */ "\x0b" "SGI xfslog" ,
189/* SGI_XLV */ "\x0c" "SGI xlv" ,
190/* SGI_XVM */ "\x0d" "SGI xvm" ,
191/* LINUX_SWAP */ "\x82" "Linux swap" ,
192/* LINUX_NATIVE */ "\x83" "Linux native",
193/* LINUX_LVM */ "\x8d" "Linux LVM" ,
194/* LINUX_RAID */ "\xfd" "Linux RAID" ,
195 NULL
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000196};
197
198
199static int
200sgi_get_nsect(void)
201{
202 return SGI_SSWAP16(sgilabel->devparam.nsect);
203}
204
205static int
206sgi_get_ntrks(void)
207{
208 return SGI_SSWAP16(sgilabel->devparam.ntrks);
209}
210
211static unsigned int
212two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
213{
214 int i = 0;
215 unsigned int sum = 0;
216
217 size /= sizeof(unsigned int);
218 for (i = 0; i < size; i++)
219 sum -= SGI_SSWAP32(base[i]);
220 return sum;
221}
222
Denis Vlasenkobd852072007-03-19 14:43:38 +0000223void BUG_bad_sgi_partition_size(void);
224
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000225static int
226check_sgi_label(void)
227{
Denis Vlasenkobd852072007-03-19 14:43:38 +0000228 if (sizeof(sgi_partition) > 512) {
229 /* According to MIPS Computer Systems, Inc the label
230 * must not contain more than 512 bytes */
231 BUG_bad_sgi_partition_size();
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000232 }
233
234 if (sgilabel->magic != SGI_LABEL_MAGIC
Denis Vlasenkobd852072007-03-19 14:43:38 +0000235 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED
236 ) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000237 current_label_type = label_dos;
238 return 0;
239 }
240
241 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
242 /*
243 * test for correct checksum
244 */
245 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
246 sizeof(*sgilabel))) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000247 printf("Detected sgi disklabel with wrong checksum\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000248 }
249 update_units();
250 current_label_type = label_sgi;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000251 g_partitions = 16;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000252 sgi_volumes = 15;
253 return 1;
254}
255
256static unsigned int
257sgi_get_start_sector(int i)
258{
259 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
260}
261
262static unsigned int
263sgi_get_num_sectors(int i)
264{
265 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
266}
267
268static int
269sgi_get_sysid(int i)
270{
271 return SGI_SSWAP32(sgilabel->partitions[i].id);
272}
273
274static int
275sgi_get_bootpartition(void)
276{
277 return SGI_SSWAP16(sgilabel->boot_part);
278}
279
280static int
281sgi_get_swappartition(void)
282{
283 return SGI_SSWAP16(sgilabel->swap_part);
284}
285
286static void
287sgi_list_table(int xtra)
288{
289 int i, w, wd;
290 int kpi = 0; /* kernel partition ID */
291
Denis Vlasenkobd852072007-03-19 14:43:38 +0000292 if (xtra) {
293 printf("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000294 "%d cylinders, %d physical cylinders\n"
295 "%d extra sects/cyl, interleave %d:1\n"
296 "%s\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000297 "Units = %s of %d * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000298 disk_device, g_heads, g_sectors, g_cylinders,
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000299 SGI_SSWAP16(sgiparam.pcylcount),
300 SGI_SSWAP16(sgiparam.sparecyl),
301 SGI_SSWAP16(sgiparam.ilfact),
302 (char *)sgilabel,
303 str_units(PLURAL), units_per_sector);
304 } else {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000305 printf("\nDisk %s (SGI disk label): "
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000306 "%d heads, %d sectors, %d cylinders\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000307 "Units = %s of %d * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000308 disk_device, g_heads, g_sectors, g_cylinders,
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000309 str_units(PLURAL), units_per_sector );
310 }
311
312 w = strlen(disk_device);
Denis Vlasenkobd852072007-03-19 14:43:38 +0000313 wd = sizeof("Device") - 1;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000314 if (w < wd)
315 w = wd;
316
Denis Vlasenkobd852072007-03-19 14:43:38 +0000317 printf("----- partitions -----\n"
318 "Pt# %*s Info Start End Sectors Id System\n",
319 w + 2, "Device");
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000320 for (i = 0; i < g_partitions; i++) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000321 if (sgi_get_num_sectors(i) || debug ) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000322 uint32_t start = sgi_get_start_sector(i);
323 uint32_t len = sgi_get_num_sectors(i);
324 kpi++; /* only count nonempty partitions */
325 printf(
326 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
327/* fdisk part number */ i+1,
328/* device */ partname(disk_device, kpi, w+3),
329/* flags */ (sgi_get_swappartition() == i) ? "swap" :
330/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
331/* start */ (long) scround(start),
332/* end */ (long) scround(start+len)-1,
333/* no odd flag on end */(long) len,
334/* type id */ sgi_get_sysid(i),
335/* type name */ partition_type(sgi_get_sysid(i)));
336 }
337 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000338 printf("----- Bootinfo -----\nBootfile: %s\n"
339 "----- Directory Entries -----\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000340 sgilabel->boot_file);
Denis Vlasenkob71c6682007-07-21 15:08:09 +0000341 for (i = 0; i < sgi_volumes; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000342 if (sgilabel->directory[i].vol_file_size) {
343 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
344 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
345 unsigned char *name = sgilabel->directory[i].vol_file_name;
346
Denis Vlasenkobd852072007-03-19 14:43:38 +0000347 printf("%2d: %-10s sector%5u size%8u\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000348 i, (char*)name, (unsigned int) start, (unsigned int) len);
349 }
350 }
351}
352
353static void
354sgi_set_bootpartition(int i)
355{
356 sgilabel->boot_part = SGI_SSWAP16(((short)i));
357}
358
359static unsigned int
360sgi_get_lastblock(void)
361{
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000362 return g_heads * g_sectors * g_cylinders;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000363}
364
365static void
366sgi_set_swappartition(int i)
367{
368 sgilabel->swap_part = SGI_SSWAP16(((short)i));
369}
370
371static int
372sgi_check_bootfile(const char* aFile)
373{
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000374 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000375 printf("\nInvalid Bootfile!\n"
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000376 "\tThe bootfile must be an absolute non-zero pathname,\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000377 "\te.g. \"/unix\" or \"/unix.save\".\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000378 return 0;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000379 }
380 if (strlen(aFile) > 16) {
381 printf("\nName of Bootfile too long (>16 bytes)\n");
382 return 0;
383 }
384 if (aFile[0] != '/') {
385 printf("\nBootfile must have a fully qualified pathname\n");
386 return 0;
387 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000388 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000389 printf("\nBe aware, that the bootfile is not checked for existence.\n"
390 "\tSGI's default is \"/unix\" and for backup \"/unix.save\".\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000391 /* filename is correct and did change */
392 return 1;
393 }
394 return 0; /* filename did not change */
395}
396
397static const char *
398sgi_get_bootfile(void)
399{
400 return (char*)sgilabel->boot_file;
401}
402
403static void
404sgi_set_bootfile(const char* aFile)
405{
406 int i = 0;
407
408 if (sgi_check_bootfile(aFile)) {
409 while (i < 16) {
410 if ((aFile[i] != '\n') /* in principle caught again by next line */
411 && (strlen(aFile) > i))
412 sgilabel->boot_file[i] = aFile[i];
413 else
414 sgilabel->boot_file[i] = 0;
415 i++;
416 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000417 printf("\n\tBootfile is changed to \"%s\"\n", sgilabel->boot_file);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000418 }
419}
420
421static void
422create_sgiinfo(void)
423{
424 /* I keep SGI's habit to write the sgilabel to the second block */
425 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
426 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
427 strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
428}
429
430static sgiinfo *fill_sgiinfo(void);
431
432static void
433sgi_write_table(void)
434{
435 sgilabel->csum = 0;
436 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
437 (unsigned int*)sgilabel, sizeof(*sgilabel)));
438 assert(two_s_complement_32bit_sum(
439 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
440
441 if (lseek(fd, 0, SEEK_SET) < 0)
442 fdisk_fatal(unable_to_seek);
443 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
444 fdisk_fatal(unable_to_write);
445 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
446 /*
447 * keep this habit of first writing the "sgilabel".
448 * I never tested whether it works without (AN 981002).
449 */
450 sgiinfo *info = fill_sgiinfo();
451 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
452 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
453 fdisk_fatal(unable_to_seek);
454 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
455 fdisk_fatal(unable_to_write);
456 free(info);
457 }
458}
459
460static int
461compare_start(int *x, int *y)
462{
463 /*
464 * sort according to start sectors
465 * and prefers largest partition:
466 * entry zero is entire disk entry
467 */
468 unsigned int i = *x;
469 unsigned int j = *y;
470 unsigned int a = sgi_get_start_sector(i);
471 unsigned int b = sgi_get_start_sector(j);
472 unsigned int c = sgi_get_num_sectors(i);
473 unsigned int d = sgi_get_num_sectors(j);
474
475 if (a == b)
476 return (d > c) ? 1 : (d == c) ? 0 : -1;
477 return (a > b) ? 1 : -1;
478}
479
480
481static int
482verify_sgi(int verbose)
483{
484 int Index[16]; /* list of valid partitions */
485 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
486 int entire = 0, i = 0;
487 unsigned int start = 0;
488 long long gap = 0; /* count unused blocks */
489 unsigned int lastblock = sgi_get_lastblock();
490
491 clearfreelist();
492 for (i = 0; i < 16; i++) {
493 if (sgi_get_num_sectors(i) != 0) {
494 Index[sortcount++] = i;
495 if (sgi_get_sysid(i) == SGI_ENTIRE_DISK) {
496 if (entire++ == 1) {
497 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000498 printf("More than one entire disk entry present\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000499 }
500 }
501 }
502 }
503 if (sortcount == 0) {
504 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000505 printf("No partitions defined\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000506 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
507 }
508 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
509 if (sgi_get_sysid(Index[0]) == SGI_ENTIRE_DISK) {
510 if ((Index[0] != 10) && verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000511 printf("IRIX likes when Partition 11 covers the entire disk\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000512 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000513 printf("The entire disk partition should start "
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000514 "at block 0,\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000515 "not at diskblock %d\n",
516 sgi_get_start_sector(Index[0]));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000517 if (debug) /* I do not understand how some disks fulfil it */
518 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000519 printf("The entire disk partition is only %d diskblock large,\n"
520 "but the disk is %d diskblocks long\n",
521 sgi_get_num_sectors(Index[0]), lastblock);
522 lastblock = sgi_get_num_sectors(Index[0]);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000523 } else {
524 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000525 printf("One Partition (#11) should cover the entire disk\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000526 if (debug > 2)
527 printf("sysid=%d\tpartition=%d\n",
528 sgi_get_sysid(Index[0]), Index[0]+1);
529 }
530 for (i = 1, start = 0; i < sortcount; i++) {
531 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
532
533 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
534 if (debug) /* I do not understand how some disks fulfil it */
535 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000536 printf("Partition %d does not start on cylinder boundary\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000537 Index[i]+1);
538 }
539 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
540 if (debug) /* I do not understand how some disks fulfil it */
541 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000542 printf("Partition %d does not end on cylinder boundary\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000543 Index[i]+1);
544 }
545 /* We cannot handle several "entire disk" entries. */
546 if (sgi_get_sysid(Index[i]) == SGI_ENTIRE_DISK) continue;
547 if (start > sgi_get_start_sector(Index[i])) {
548 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000549 printf("Partitions %d and %d overlap by %d sectors\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000550 Index[i-1]+1, Index[i]+1,
551 start - sgi_get_start_sector(Index[i]));
Denis Vlasenkobd852072007-03-19 14:43:38 +0000552 if (gap > 0) gap = -gap;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000553 if (gap == 0) gap = -1;
554 }
555 if (start < sgi_get_start_sector(Index[i])) {
556 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000557 printf("Unused gap of %8u sectors - sectors %8u-%8u\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000558 sgi_get_start_sector(Index[i]) - start,
559 start, sgi_get_start_sector(Index[i])-1);
560 gap += sgi_get_start_sector(Index[i]) - start;
561 add2freelist(start, sgi_get_start_sector(Index[i]));
562 }
563 start = sgi_get_start_sector(Index[i])
564 + sgi_get_num_sectors(Index[i]);
565 if (debug > 1) {
566 if (verbose)
567 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
568 sgi_get_start_sector(Index[i]),
569 sgi_get_num_sectors(Index[i]),
570 sgi_get_sysid(Index[i]));
571 }
572 }
573 if (start < lastblock) {
574 if (verbose)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000575 printf("Unused gap of %8u sectors - sectors %8u-%8u\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000576 lastblock - start, start, lastblock-1);
577 gap += lastblock - start;
578 add2freelist(start, lastblock);
579 }
580 /*
581 * Done with arithmetics
582 * Go for details now
583 */
584 if (verbose) {
585 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000586 printf("\nThe boot partition does not exist\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000587 }
588 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000589 printf("\nThe swap partition does not exist\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000590 } else {
591 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
592 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
Denis Vlasenkobd852072007-03-19 14:43:38 +0000593 printf("\nThe swap partition has no swap type\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000594 }
595 if (sgi_check_bootfile("/unix"))
Denis Vlasenkobd852072007-03-19 14:43:38 +0000596 printf("\tYou have chosen an unusual boot file name\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000597 }
598 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
599}
600
601static int
602sgi_gaps(void)
603{
604 /*
605 * returned value is:
606 * = 0 : disk is properly filled to the rim
607 * < 0 : there is an overlap
608 * > 0 : there is still some vacant space
609 */
610 return verify_sgi(0);
611}
612
613static void
614sgi_change_sysid(int i, int sys)
615{
Denis Vlasenko219d14d2007-03-24 15:40:16 +0000616 if (sgi_get_num_sectors(i) == 0) { /* caught already before, ... */
Denis Vlasenkobd852072007-03-19 14:43:38 +0000617 printf("Sorry you may change the Tag of non-empty partitions\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000618 return;
619 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000620 if ((sys != SGI_ENTIRE_DISK) && (sys != SGI_VOLHDR)
621 && (sgi_get_start_sector(i) < 1)
622 ) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000623 read_maybe_empty(
Denis Vlasenkobd852072007-03-19 14:43:38 +0000624 "It is highly recommended that the partition at offset 0\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000625 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
626 "retrieve from its directory standalone tools like sash and fx.\n"
627 "Only the \"SGI volume\" entire disk section may violate this.\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000628 "Type YES if you are sure about tagging this partition differently.\n");
629 if (strcmp(line_ptr, "YES\n") != 0)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000630 return;
631 }
632 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
633}
634
635/* returns partition index of first entry marked as entire disk */
636static int
637sgi_entire(void)
638{
639 int i;
640
641 for (i = 0; i < 16; i++)
642 if (sgi_get_sysid(i) == SGI_VOLUME)
643 return i;
644 return -1;
645}
646
647static void
648sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
649{
650 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
651 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
652 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
653 set_changed(i);
654 if (sgi_gaps() < 0) /* rebuild freelist */
Denis Vlasenkobd852072007-03-19 14:43:38 +0000655 printf("Partition overlap detected\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000656}
657
658static void
659sgi_set_entire(void)
660{
661 int n;
662
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000663 for (n = 10; n < g_partitions; n++) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000664 if (!sgi_get_num_sectors(n) ) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000665 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
666 break;
667 }
668 }
669}
670
671static void
672sgi_set_volhdr(void)
673{
674 int n;
675
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000676 for (n = 8; n < g_partitions; n++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000677 if (!sgi_get_num_sectors(n)) {
678 /*
679 * 5 cylinders is an arbitrary value I like
680 * IRIX 5.3 stored files in the volume header
681 * (like sash, symmon, fx, ide) with ca. 3200
682 * sectors.
683 */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000684 if (g_heads * g_sectors * 5 < sgi_get_lastblock())
685 sgi_set_partition(n, 0, g_heads * g_sectors * 5, SGI_VOLHDR);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000686 break;
687 }
688 }
689}
690
691static void
692sgi_delete_partition(int i)
693{
694 sgi_set_partition(i, 0, 0, 0);
695}
696
697static void
698sgi_add_partition(int n, int sys)
699{
700 char mesg[256];
701 unsigned int first = 0, last = 0;
702
703 if (n == 10) {
704 sys = SGI_VOLUME;
705 } else if (n == 8) {
706 sys = 0;
707 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000708 if (sgi_get_num_sectors(n)) {
709 printf(msg_part_already_defined, n + 1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000710 return;
711 }
712 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000713 printf("Attempting to generate entire disk entry automatically\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000714 sgi_set_entire();
715 sgi_set_volhdr();
716 }
717 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000718 printf("The entire disk is already covered with partitions\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000719 return;
720 }
721 if (sgi_gaps() < 0) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000722 printf("You got a partition overlap on the disk. Fix it first!\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000723 return;
724 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000725 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000726 while (1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000727 if (sys == SGI_VOLUME) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000728 last = sgi_get_lastblock();
729 first = read_int(0, 0, last-1, 0, mesg);
730 if (first != 0) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000731 printf("It is highly recommended that eleventh partition\n"
732 "covers the entire disk and is of type 'SGI volume'\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000733 }
734 } else {
735 first = freelist[0].first;
736 last = freelist[0].last;
737 first = read_int(scround(first), scround(first), scround(last)-1,
738 0, mesg);
739 }
740 if (display_in_cyl_units)
741 first *= units_per_sector;
742 else
743 first = first; /* align to cylinder if you know how ... */
Denis Vlasenkobd852072007-03-19 14:43:38 +0000744 if (!last )
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000745 last = isinfreelist(first);
Denis Vlasenkobd852072007-03-19 14:43:38 +0000746 if (last != 0)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000747 break;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000748 printf("You will get a partition overlap on the disk. "
749 "Fix it first!\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000750 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000751 snprintf(mesg, sizeof(mesg), " Last %s", str_units(SINGULAR));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000752 last = read_int(scround(first), scround(last)-1, scround(last)-1,
753 scround(first), mesg)+1;
754 if (display_in_cyl_units)
755 last *= units_per_sector;
756 else
757 last = last; /* align to cylinder if You know how ... */
758 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
Denis Vlasenkobd852072007-03-19 14:43:38 +0000759 printf("It is highly recommended that eleventh partition\n"
760 "covers the entire disk and is of type 'SGI volume'\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000761 sgi_set_partition(n, first, last-first, sys);
762}
763
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000764#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000765static void
766create_sgilabel(void)
767{
768 struct hd_geometry geometry;
769 struct {
770 unsigned int start;
771 unsigned int nsect;
772 int sysid;
773 } old[4];
774 int i = 0;
775 long longsectors; /* the number of sectors on the device */
776 int res; /* the result from the ioctl */
777 int sec_fac; /* the sector factor */
778
779 sec_fac = sector_size / 512; /* determine the sector factor */
780
Denis Vlasenkobd852072007-03-19 14:43:38 +0000781 printf(msg_building_new_label, "SGI disklabel");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000782
783 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
784 res = ioctl(fd, BLKGETSIZE, &longsectors);
785 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000786 g_heads = geometry.heads;
787 g_sectors = geometry.sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000788 if (res == 0) {
789 /* the get device size ioctl was successful */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000790 g_cylinders = longsectors / (g_heads * g_sectors);
791 g_cylinders /= sec_fac;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000792 } else {
793 /* otherwise print error and use truncated version */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000794 g_cylinders = geometry.cylinders;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000795 printf(
796"Warning: BLKGETSIZE ioctl failed on %s. Using geometry cylinder value of %d.\n"
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000797"This value may be truncated for devices > 33.8 GB.\n", disk_device, g_cylinders);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000798 }
799 }
800 for (i = 0; i < 4; i++) {
801 old[i].sysid = 0;
802 if (valid_part_table_flag(MBRbuffer)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000803 if (get_part_table(i)->sys_ind) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000804 old[i].sysid = get_part_table(i)->sys_ind;
805 old[i].start = get_start_sect(get_part_table(i));
806 old[i].nsect = get_nr_sects(get_part_table(i));
Denis Vlasenkobd852072007-03-19 14:43:38 +0000807 printf("Trying to keep parameters of partition %d\n", i);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000808 if (debug)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000809 printf("ID=%02x\tSTART=%d\tLENGTH=%d\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000810 old[i].sysid, old[i].start, old[i].nsect);
811 }
812 }
813 }
814
815 memset(MBRbuffer, 0, sizeof(MBRbuffer));
Denis Vlasenkod5470832007-01-03 02:58:54 +0000816 /* fields with '//' are already zeroed out by memset above */
817
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000818 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
Denis Vlasenkod5470832007-01-03 02:58:54 +0000819 //sgilabel->boot_part = SGI_SSWAP16(0);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000820 sgilabel->swap_part = SGI_SSWAP16(1);
821
Denis Vlasenkod5470832007-01-03 02:58:54 +0000822 //memset(sgilabel->boot_file, 0, 16);
823 strcpy((char*)sgilabel->boot_file, "/unix"); /* sizeof(sgilabel->boot_file) == 16 > 6 */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000824
Denis Vlasenkod5470832007-01-03 02:58:54 +0000825 //sgilabel->devparam.skew = (0);
826 //sgilabel->devparam.gap1 = (0);
827 //sgilabel->devparam.gap2 = (0);
828 //sgilabel->devparam.sparecyl = (0);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000829 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
Denis Vlasenkod5470832007-01-03 02:58:54 +0000830 //sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
831 /* tracks/cylinder (heads) */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000832 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Denis Vlasenkod5470832007-01-03 02:58:54 +0000833 //sgilabel->devparam.cmd_tag_queue_depth = (0);
834 //sgilabel->devparam.unused0 = (0);
835 //sgilabel->devparam.unused1 = SGI_SSWAP16(0);
836 /* sectors/track */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000837 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000838 sgilabel->devparam.bytes = SGI_SSWAP16(512);
839 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
840 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
841 IGNORE_ERRORS|RESEEK);
Denis Vlasenkod5470832007-01-03 02:58:54 +0000842 //sgilabel->devparam.datarate = SGI_SSWAP32(0);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000843 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
Denis Vlasenkod5470832007-01-03 02:58:54 +0000844 //sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
845 //sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
846 //sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
847 //sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
848 //sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
849 //sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
850 //sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
851 //memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
852 //memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partinfo)*16 );
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000853 current_label_type = label_sgi;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000854 g_partitions = 16;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000855 sgi_volumes = 15;
856 sgi_set_entire();
857 sgi_set_volhdr();
858 for (i = 0; i < 4; i++) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000859 if (old[i].sysid) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000860 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
861 }
862 }
863}
864
865static void
866sgi_set_xcyl(void)
867{
868 /* do nothing in the beginning */
869}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000870#endif /* FEATURE_FDISK_ADVANCED */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000871
872/* _____________________________________________________________
873 */
874
875static sgiinfo *
876fill_sgiinfo(void)
877{
Denis Vlasenko9b1381f2007-01-03 02:56:00 +0000878 sgiinfo *info = xzalloc(sizeof(sgiinfo));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000879
880 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
881 info->b1 = SGI_SSWAP32(-1);
882 info->b2 = SGI_SSWAP16(-1);
883 info->b3 = SGI_SSWAP16(1);
884 /* You may want to replace this string !!!!!!! */
885 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
886 strcpy( (char*)info->serial, "0000" );
887 info->check1816 = SGI_SSWAP16(18*256 +16 );
888 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
889 return info;
890}
891#endif /* SGI_LABEL */