1 /*
2  * Copyright (C) Andreas Neuper, Sep 1998.
3  *
4  * Licensed under GPLv2, see file LICENSE in this source tree.
5  */
6 
7 #if ENABLE_FEATURE_SGI_LABEL
8 
9 #define SGI_DEBUG 0
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
setfreelist(int i,unsigned int f,unsigned int l)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
add2freelist(unsigned int f,unsigned int l)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
clearfreelist(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
isinfreelist(unsigned int b)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
sgi_get_nsect(void)201 sgi_get_nsect(void)
202 {
203 	return SGI_SSWAP16(sgilabel->devparam.nsect);
204 }
205 
206 static int
sgi_get_ntrks(void)207 sgi_get_ntrks(void)
208 {
209 	return SGI_SSWAP16(sgilabel->devparam.ntrks);
210 }
211 
212 static unsigned int
two_s_complement_32bit_sum(unsigned int * base,int size)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
check_sgi_label(void)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
sgi_get_start_sector(int i)258 sgi_get_start_sector(int i)
259 {
260 	return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
261 }
262 
263 static unsigned int
sgi_get_num_sectors(int i)264 sgi_get_num_sectors(int i)
265 {
266 	return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
267 }
268 
269 static int
sgi_get_sysid(int i)270 sgi_get_sysid(int i)
271 {
272 	return SGI_SSWAP32(sgilabel->partitions[i].id);
273 }
274 
275 static int
sgi_get_bootpartition(void)276 sgi_get_bootpartition(void)
277 {
278 	return SGI_SSWAP16(sgilabel->boot_part);
279 }
280 
281 static int
sgi_get_swappartition(void)282 sgi_get_swappartition(void)
283 {
284 	return SGI_SSWAP16(sgilabel->swap_part);
285 }
286 
287 static void
sgi_list_table(int xtra)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): %u heads, %u sectors\n"
295 			"%u cylinders, %u physical cylinders\n"
296 			"%u extra sects/cyl, interleave %u:1\n"
297 			"%s\n"
298 			"Units = %s of %u * 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 			"%u heads, %u sectors, %u cylinders\n"
308 			"Units = %s of %u * 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 			"%2u: %s %4s %9lu %9lu %9lu  %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("%2u: %-10s sector%5u size%8u\n",
349 				i, (char*)name, (unsigned int) start, (unsigned int) len);
350 		}
351 	}
352 }
353 
354 static void
sgi_set_bootpartition(int i)355 sgi_set_bootpartition(int i)
356 {
357 	sgilabel->boot_part = SGI_SSWAP16(((short)i));
358 }
359 
360 static unsigned int
sgi_get_lastblock(void)361 sgi_get_lastblock(void)
362 {
363 	return g_heads * g_sectors * g_cylinders;
364 }
365 
366 static void
sgi_set_swappartition(int i)367 sgi_set_swappartition(int i)
368 {
369 	sgilabel->swap_part = SGI_SSWAP16(((short)i));
370 }
371 
372 static int
sgi_check_bootfile(const char * aFile)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 *
sgi_get_bootfile(void)399 sgi_get_bootfile(void)
400 {
401 	return (char*)sgilabel->boot_file;
402 }
403 
404 static void
sgi_set_bootfile(const char * aFile)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
create_sgiinfo(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
sgi_write_table(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 	write_sector(0, sgilabel);
443 	if (is_prefixed_with((char*)sgilabel->directory[0].vol_file_name, "sgilabel")) {
444 		/*
445 		 * keep this habit of first writing the "sgilabel".
446 		 * I never tested whether it works without (AN 981002).
447 		 */
448 		sgiinfo *info = fill_sgiinfo();
449 		int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
450 		write_sector(infostartblock, info);
451 		free(info);
452 	}
453 }
454 
455 static int
compare_start(int * x,int * y)456 compare_start(int *x, int *y)
457 {
458 	/*
459 	 * sort according to start sectors
460 	 * and prefers largest partition:
461 	 * entry zero is entire disk entry
462 	 */
463 	unsigned int i = *x;
464 	unsigned int j = *y;
465 	unsigned int a = sgi_get_start_sector(i);
466 	unsigned int b = sgi_get_start_sector(j);
467 	unsigned int c = sgi_get_num_sectors(i);
468 	unsigned int d = sgi_get_num_sectors(j);
469 
470 	if (a == b)
471 		return (d > c) ? 1 : (d == c) ? 0 : -1;
472 	return (a > b) ? 1 : -1;
473 }
474 
475 
476 static int
verify_sgi(int verbose)477 verify_sgi(int verbose)
478 {
479 	int Index[16];      /* list of valid partitions */
480 	int sortcount = 0;  /* number of used partitions, i.e. non-zero lengths */
481 	int entire = 0, i = 0;
482 	unsigned int start = 0;
483 	long long gap = 0;      /* count unused blocks */
484 	unsigned int lastblock = sgi_get_lastblock();
485 
486 	clearfreelist();
487 	for (i = 0; i < 16; i++) {
488 		if (sgi_get_num_sectors(i) != 0) {
489 			Index[sortcount++] = i;
490 			if (sgi_get_sysid(i) == SGI_ENTIRE_DISK) {
491 				if (entire++ == 1) {
492 					if (verbose)
493 						printf("More than one entire disk entry present\n");
494 				}
495 			}
496 		}
497 	}
498 	if (sortcount == 0) {
499 		if (verbose)
500 			printf("No partitions defined\n");
501 		return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
502 	}
503 	qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
504 	if (sgi_get_sysid(Index[0]) == SGI_ENTIRE_DISK) {
505 		if ((Index[0] != 10) && verbose)
506 			printf("IRIX likes when Partition 11 covers the entire disk\n");
507 		if ((sgi_get_start_sector(Index[0]) != 0) && verbose) {
508 			printf("The entire disk partition should start "
509 				"at block 0,\n"
510 				"not at diskblock %u\n",
511 				sgi_get_start_sector(Index[0]));
512 		}
513 		if (SGI_DEBUG) {     /* I do not understand how some disks fulfil it */
514 			if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
515 				printf("The entire disk partition is only %u diskblock large,\n"
516 					"but the disk is %u diskblocks long\n",
517 					sgi_get_num_sectors(Index[0]), lastblock);
518 			lastblock = sgi_get_num_sectors(Index[0]);
519 		}
520 	} else {
521 		if (verbose)
522 			printf("One Partition (#11) should cover the entire disk\n");
523 		if (SGI_DEBUG > 2)
524 			printf("sysid=%u\tpartition=%u\n",
525 				sgi_get_sysid(Index[0]), Index[0]+1);
526 	}
527 	for (i = 1, start = 0; i < sortcount; i++) {
528 		int cylsize = sgi_get_nsect() * sgi_get_ntrks();
529 
530 		if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
531 			if (SGI_DEBUG)      /* I do not understand how some disks fulfil it */
532 				if (verbose)
533 					printf("Partition %u does not start on cylinder boundary\n",
534 						Index[i]+1);
535 		}
536 		if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
537 			if (SGI_DEBUG)      /* I do not understand how some disks fulfil it */
538 				if (verbose)
539 					printf("Partition %u does not end on cylinder boundary\n",
540 						Index[i]+1);
541 		}
542 		/* We cannot handle several "entire disk" entries. */
543 		if (sgi_get_sysid(Index[i]) == SGI_ENTIRE_DISK) continue;
544 		if (start > sgi_get_start_sector(Index[i])) {
545 			if (verbose)
546 				printf("Partitions %u and %u overlap by %u sectors\n",
547 					Index[i-1]+1, Index[i]+1,
548 					start - sgi_get_start_sector(Index[i]));
549 			if (gap > 0) gap = -gap;
550 			if (gap == 0) gap = -1;
551 		}
552 		if (start < sgi_get_start_sector(Index[i])) {
553 			if (verbose)
554 				printf("Unused gap of %u sectors - sectors %u-%u\n",
555 					sgi_get_start_sector(Index[i]) - start,
556 					start, sgi_get_start_sector(Index[i])-1);
557 			gap += sgi_get_start_sector(Index[i]) - start;
558 			add2freelist(start, sgi_get_start_sector(Index[i]));
559 		}
560 		start = sgi_get_start_sector(Index[i])
561 			   + sgi_get_num_sectors(Index[i]);
562 		if (SGI_DEBUG > 1) {
563 			if (verbose)
564 				printf("%2u:%12u\t%12u\t%12u\n", Index[i],
565 					sgi_get_start_sector(Index[i]),
566 					sgi_get_num_sectors(Index[i]),
567 					sgi_get_sysid(Index[i]));
568 		}
569 	}
570 	if (start < lastblock) {
571 		if (verbose)
572 			printf("Unused gap of %u sectors - sectors %u-%u\n",
573 				lastblock - start, start, lastblock-1);
574 		gap += lastblock - start;
575 		add2freelist(start, lastblock);
576 	}
577 	/*
578 	 * Done with arithmetics
579 	 * Go for details now
580 	 */
581 	if (verbose) {
582 		if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
583 			printf("\nThe boot partition does not exist\n");
584 		}
585 		if (!sgi_get_num_sectors(sgi_get_swappartition())) {
586 			printf("\nThe swap partition does not exist\n");
587 		} else {
588 			if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
589 			 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
590 				printf("\nThe swap partition has no swap type\n");
591 		}
592 		if (sgi_check_bootfile("/unix"))
593 			printf("\tYou have chosen an unusual boot file name\n");
594 	}
595 	return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
596 }
597 
598 static int
sgi_gaps(void)599 sgi_gaps(void)
600 {
601 	/*
602 	 * returned value is:
603 	 *  = 0 : disk is properly filled to the rim
604 	 *  < 0 : there is an overlap
605 	 *  > 0 : there is still some vacant space
606 	 */
607 	return verify_sgi(0);
608 }
609 
610 static void
sgi_change_sysid(int i,int sys)611 sgi_change_sysid(int i, int sys)
612 {
613 	if (sgi_get_num_sectors(i) == 0) { /* caught already before, ... */
614 		printf("Sorry you may change the Tag of non-empty partitions\n");
615 		return;
616 	}
617 	if ((sys != SGI_ENTIRE_DISK) && (sys != SGI_VOLHDR)
618 	 && (sgi_get_start_sector(i) < 1)
619 	) {
620 		read_maybe_empty(
621 			"It is highly recommended that the partition at offset 0\n"
622 			"is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
623 			"retrieve from its directory standalone tools like sash and fx.\n"
624 			"Only the \"SGI volume\" entire disk section may violate this.\n"
625 			"Type YES if you are sure about tagging this partition differently.\n");
626 		if (strcmp(line_ptr, "YES\n") != 0)
627 			return;
628 	}
629 	sgilabel->partitions[i].id = SGI_SSWAP32(sys);
630 }
631 
632 /* returns partition index of first entry marked as entire disk */
633 static int
sgi_entire(void)634 sgi_entire(void)
635 {
636 	int i;
637 
638 	for (i = 0; i < 16; i++)
639 		if (sgi_get_sysid(i) == SGI_VOLUME)
640 			return i;
641 	return -1;
642 }
643 
644 static void
sgi_set_partition(int i,unsigned int start,unsigned int length,int sys)645 sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
646 {
647 	sgilabel->partitions[i].id = SGI_SSWAP32(sys);
648 	sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
649 	sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
650 	set_changed(i);
651 	if (sgi_gaps() < 0)     /* rebuild freelist */
652 		printf("Partition overlap detected\n");
653 }
654 
655 static void
sgi_set_entire(void)656 sgi_set_entire(void)
657 {
658 	int n;
659 
660 	for (n = 10; n < g_partitions; n++) {
661 		if (!sgi_get_num_sectors(n) ) {
662 			sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
663 			break;
664 		}
665 	}
666 }
667 
668 static void
sgi_set_volhdr(void)669 sgi_set_volhdr(void)
670 {
671 	int n;
672 
673 	for (n = 8; n < g_partitions; n++) {
674 		if (!sgi_get_num_sectors(n)) {
675 			/*
676 			 * 5 cylinders is an arbitrary value I like
677 			 * IRIX 5.3 stored files in the volume header
678 			 * (like sash, symmon, fx, ide) with ca. 3200
679 			 * sectors.
680 			 */
681 			if (g_heads * g_sectors * 5 < sgi_get_lastblock()) {
682 				sgi_set_partition(n, 0, g_heads * g_sectors * 5, SGI_VOLHDR);
683 				break;
684 			}
685 		}
686 	}
687 }
688 
689 static void
sgi_delete_partition(int i)690 sgi_delete_partition(int i)
691 {
692 	sgi_set_partition(i, 0, 0, 0);
693 }
694 
695 static void
sgi_add_partition(int n,int sys)696 sgi_add_partition(int n, int sys)
697 {
698 	char mesg[256];
699 	unsigned int first = 0, last = 0;
700 
701 	if (n == 10) {
702 		sys = SGI_VOLUME;
703 	} else if (n == 8) {
704 		sys = 0;
705 	}
706 	if (sgi_get_num_sectors(n)) {
707 		printf(msg_part_already_defined, n + 1);
708 		return;
709 	}
710 	if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
711 		printf("Attempting to generate entire disk entry automatically\n");
712 		sgi_set_entire();
713 		sgi_set_volhdr();
714 	}
715 	if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
716 		printf("The entire disk is already covered with partitions\n");
717 		return;
718 	}
719 	if (sgi_gaps() < 0) {
720 		printf("You got a partition overlap on the disk. Fix it first!\n");
721 		return;
722 	}
723 	snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
724 	while (1) {
725 		if (sys == SGI_VOLUME) {
726 			last = sgi_get_lastblock();
727 			first = read_int(0, 0, last-1, 0, mesg);
728 			if (first != 0) {
729 				printf("It is highly recommended that eleventh partition\n"
730 						"covers the entire disk and is of type 'SGI volume'\n");
731 			}
732 		} else {
733 			first = freelist[0].first;
734 			last  = freelist[0].last;
735 			first = read_int(scround(first), scround(first), scround(last)-1,
736 				0, mesg);
737 		}
738 		if (display_in_cyl_units)
739 			first *= units_per_sector;
740 		else
741 			first = first; /* align to cylinder if you know how ... */
742 		if (!last )
743 			last = isinfreelist(first);
744 		if (last != 0)
745 			break;
746 		printf("You will get a partition overlap on the disk. "
747 				"Fix it first!\n");
748 	}
749 	snprintf(mesg, sizeof(mesg), " Last %s", str_units(SINGULAR));
750 	last = read_int(scround(first), scround(last)-1, scround(last)-1,
751 			scround(first), mesg)+1;
752 	if (display_in_cyl_units)
753 		last *= units_per_sector;
754 	else
755 		last = last; /* align to cylinder if You know how ... */
756 	if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
757 		printf("It is highly recommended that eleventh partition\n"
758 			"covers the entire disk and is of type 'SGI volume'\n");
759 	sgi_set_partition(n, first, last-first, sys);
760 }
761 
762 #if ENABLE_FEATURE_FDISK_ADVANCED
763 static void
create_sgilabel(void)764 create_sgilabel(void)
765 {
766 	struct hd_geometry geometry;
767 	struct {
768 		unsigned int start;
769 		unsigned int nsect;
770 		int sysid;
771 	} old[4];
772 	int i = 0;
773 	long longsectors;               /* the number of sectors on the device */
774 	int res;                        /* the result from the ioctl */
775 	int sec_fac;                    /* the sector factor */
776 
777 	sec_fac = sector_size / 512;    /* determine the sector factor */
778 
779 	printf(msg_building_new_label, "SGI disklabel");
780 
781 	sgi_other_endian = BB_LITTLE_ENDIAN;
782 	res = ioctl(dev_fd, BLKGETSIZE, &longsectors);
783 	if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
784 		g_heads = geometry.heads;
785 		g_sectors = geometry.sectors;
786 		if (res == 0) {
787 			/* the get device size ioctl was successful */
788 			g_cylinders = longsectors / (g_heads * g_sectors);
789 			g_cylinders /= sec_fac;
790 		} else {
791 			/* otherwise print error and use truncated version */
792 			g_cylinders = geometry.cylinders;
793 			printf(
794 "Warning: BLKGETSIZE ioctl failed on %s.  Using geometry cylinder value of %u.\n"
795 "This value may be truncated for devices > 33.8 GB.\n", disk_device, g_cylinders);
796 		}
797 	}
798 	for (i = 0; i < 4; i++) {
799 		old[i].sysid = 0;
800 		if (valid_part_table_flag(MBRbuffer)) {
801 			if (get_part_table(i)->sys_ind) {
802 				old[i].sysid = get_part_table(i)->sys_ind;
803 				old[i].start = get_start_sect(get_part_table(i));
804 				old[i].nsect = get_nr_sects(get_part_table(i));
805 				printf("Trying to keep parameters of partition %u\n", i);
806 				if (SGI_DEBUG)
807 					printf("ID=%02x\tSTART=%u\tLENGTH=%u\n",
808 				old[i].sysid, old[i].start, old[i].nsect);
809 			}
810 		}
811 	}
812 
813 	memset(MBRbuffer, 0, sizeof(MBRbuffer));
814 	/* fields with '//' are already zeroed out by memset above */
815 
816 	sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
817 	//sgilabel->boot_part = SGI_SSWAP16(0);
818 	sgilabel->swap_part = SGI_SSWAP16(1);
819 
820 	//memset(sgilabel->boot_file, 0, 16);
821 	strcpy((char*)sgilabel->boot_file, "/unix"); /* sizeof(sgilabel->boot_file) == 16 > 6 */
822 
823 	//sgilabel->devparam.skew                     = (0);
824 	//sgilabel->devparam.gap1                     = (0);
825 	//sgilabel->devparam.gap2                     = (0);
826 	//sgilabel->devparam.sparecyl                 = (0);
827 	sgilabel->devparam.pcylcount                = SGI_SSWAP16(geometry.cylinders);
828 	//sgilabel->devparam.head_vol0                = SGI_SSWAP16(0);
829 	/* tracks/cylinder (heads) */
830 	sgilabel->devparam.ntrks                    = SGI_SSWAP16(geometry.heads);
831 	//sgilabel->devparam.cmd_tag_queue_depth      = (0);
832 	//sgilabel->devparam.unused0                  = (0);
833 	//sgilabel->devparam.unused1                  = SGI_SSWAP16(0);
834 	/* sectors/track */
835 	sgilabel->devparam.nsect                    = SGI_SSWAP16(geometry.sectors);
836 	sgilabel->devparam.bytes                    = SGI_SSWAP16(512);
837 	sgilabel->devparam.ilfact                   = SGI_SSWAP16(1);
838 	sgilabel->devparam.flags                    = SGI_SSWAP32(TRACK_FWD|
839 							IGNORE_ERRORS|RESEEK);
840 	//sgilabel->devparam.datarate                 = SGI_SSWAP32(0);
841 	sgilabel->devparam.retries_on_error         = SGI_SSWAP32(1);
842 	//sgilabel->devparam.ms_per_word              = SGI_SSWAP32(0);
843 	//sgilabel->devparam.xylogics_gap1            = SGI_SSWAP16(0);
844 	//sgilabel->devparam.xylogics_syncdelay       = SGI_SSWAP16(0);
845 	//sgilabel->devparam.xylogics_readdelay       = SGI_SSWAP16(0);
846 	//sgilabel->devparam.xylogics_gap2            = SGI_SSWAP16(0);
847 	//sgilabel->devparam.xylogics_readgate        = SGI_SSWAP16(0);
848 	//sgilabel->devparam.xylogics_writecont       = SGI_SSWAP16(0);
849 	//memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
850 	//memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partinfo)*16 );
851 	current_label_type = LABEL_SGI;
852 	g_partitions = 16;
853 	sgi_volumes = 15;
854 	sgi_set_entire();
855 	sgi_set_volhdr();
856 	for (i = 0; i < 4; i++) {
857 		if (old[i].sysid) {
858 			sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
859 		}
860 	}
861 }
862 
863 static void
sgi_set_xcyl(void)864 sgi_set_xcyl(void)
865 {
866 	/* do nothing in the beginning */
867 }
868 #endif /* FEATURE_FDISK_ADVANCED */
869 
870 /* _____________________________________________________________
871  */
872 
873 static sgiinfo *
fill_sgiinfo(void)874 fill_sgiinfo(void)
875 {
876 	sgiinfo *info = xzalloc(sizeof(sgiinfo));
877 
878 	info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
879 	info->b1 = SGI_SSWAP32(-1);
880 	info->b2 = SGI_SSWAP16(-1);
881 	info->b3 = SGI_SSWAP16(1);
882 	/* You may want to replace this string !!!!!!! */
883 	strcpy( (char*)info->scsi_string, "IBM OEM 0662S12         3 30" );
884 	strcpy( (char*)info->serial, "0000" );
885 	info->check1816 = SGI_SSWAP16(18*256 +16 );
886 	strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
887 	return info;
888 }
889 #endif /* SGI_LABEL */
890