1 /*
2  * fdisk_sun.c
3  *
4  * I think this is mostly, or entirely, due to
5  *      Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
6  *
7  * Merged with fdisk for other architectures, aeb, June 1998.
8  *
9  * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
10  *      Internationalization
11  *
12  * Licensed under GPLv2, see file LICENSE in this source tree.
13  */
14 
15 #if ENABLE_FEATURE_SUN_LABEL
16 
17 #define SUNOS_SWAP 3
18 #define SUN_WHOLE_DISK 5
19 
20 #define SUN_LABEL_MAGIC          0xDABE
21 #define SUN_LABEL_MAGIC_SWAPPED  0xBEDA
22 #define SUN_SSWAP16(x) (sun_other_endian ? fdisk_swap16(x) : (uint16_t)(x))
23 #define SUN_SSWAP32(x) (sun_other_endian ? fdisk_swap32(x) : (uint32_t)(x))
24 
25 /* Copied from linux/major.h */
26 #define FLOPPY_MAJOR    2
27 
28 #define SCSI_IOCTL_GET_IDLUN 0x5382
29 
30 static smallint sun_other_endian;
31 static smallint scsi_disk;
32 static smallint floppy;
33 
34 #ifndef IDE0_MAJOR
35 #define IDE0_MAJOR 3
36 #endif
37 #ifndef IDE1_MAJOR
38 #define IDE1_MAJOR 22
39 #endif
40 
41 static void
guess_device_type(void)42 guess_device_type(void)
43 {
44 	struct stat bootstat;
45 
46 	if (fstat(dev_fd, &bootstat) < 0) {
47 		scsi_disk = 0;
48 		floppy = 0;
49 	} else if (S_ISBLK(bootstat.st_mode)
50 		&& (major(bootstat.st_rdev) == IDE0_MAJOR ||
51 		    major(bootstat.st_rdev) == IDE1_MAJOR)) {
52 		scsi_disk = 0;
53 		floppy = 0;
54 	} else if (S_ISBLK(bootstat.st_mode)
55 		&& major(bootstat.st_rdev) == FLOPPY_MAJOR) {
56 		scsi_disk = 0;
57 		floppy = 1;
58 	} else {
59 		scsi_disk = 1;
60 		floppy = 0;
61 	}
62 }
63 
64 static const char *const sun_sys_types[] = {
65 	"\x00" "Empty"       , /* 0            */
66 	"\x01" "Boot"        , /* 1            */
67 	"\x02" "SunOS root"  , /* 2            */
68 	"\x03" "SunOS swap"  , /* SUNOS_SWAP   */
69 	"\x04" "SunOS usr"   , /* 4            */
70 	"\x05" "Whole disk"  , /* SUN_WHOLE_DISK   */
71 	"\x06" "SunOS stand" , /* 6            */
72 	"\x07" "SunOS var"   , /* 7            */
73 	"\x08" "SunOS home"  , /* 8            */
74 	"\x82" "Linux swap"  , /* LINUX_SWAP   */
75 	"\x83" "Linux native", /* LINUX_NATIVE */
76 	"\x8e" "Linux LVM"   , /* 0x8e         */
77 /* New (2.2.x) raid partition with autodetect using persistent superblock */
78 	"\xfd" "Linux raid autodetect", /* 0xfd         */
79 	NULL
80 };
81 
82 
83 static void
set_sun_partition(int i,unsigned start,unsigned stop,int sysid)84 set_sun_partition(int i, unsigned start, unsigned stop, int sysid)
85 {
86 	sunlabel->infos[i].id = sysid;
87 	sunlabel->partitions[i].start_cylinder =
88 		SUN_SSWAP32(start / (g_heads * g_sectors));
89 	sunlabel->partitions[i].num_sectors =
90 		SUN_SSWAP32(stop - start);
91 	set_changed(i);
92 }
93 
94 static int
check_sun_label(void)95 check_sun_label(void)
96 {
97 	unsigned short *ush;
98 	int csum;
99 
100 	if (sunlabel->magic != SUN_LABEL_MAGIC
101 	 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED
102 	) {
103 		current_label_type = LABEL_DOS;
104 		sun_other_endian = 0;
105 		return 0;
106 	}
107 	sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
108 	ush = ((unsigned short *) (sunlabel + 1)) - 1;
109 	for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
110 	if (csum) {
111 		printf("Detected sun disklabel with wrong checksum.\n"
112 "Probably you'll have to set all the values,\n"
113 "e.g. heads, sectors, cylinders and partitions\n"
114 "or force a fresh label (s command in main menu)\n");
115 	} else {
116 		g_heads = SUN_SSWAP16(sunlabel->ntrks);
117 		g_cylinders = SUN_SSWAP16(sunlabel->ncyl);
118 		g_sectors = SUN_SSWAP16(sunlabel->nsect);
119 	}
120 	update_units();
121 	current_label_type = LABEL_SUN;
122 	g_partitions = 8;
123 	return 1;
124 }
125 
126 static const struct sun_predefined_drives {
127 	const char *vendor;
128 	const char *model;
129 	unsigned short sparecyl;
130 	unsigned short ncyl;
131 	unsigned short nacyl;
132 	unsigned short pcylcount;
133 	unsigned short ntrks;
134 	unsigned short nsect;
135 	unsigned short rspeed;
136 } sun_drives[] = {
137 	{ "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
138 	{ "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
139 	{ "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
140 	{ "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
141 	{ "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
142 	{ "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
143 	{ "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
144 	{ "","SUN0104",1,974,2,1019,6,35,3662},
145 	{ "","SUN0207",4,1254,2,1272,9,36,3600},
146 	{ "","SUN0327",3,1545,2,1549,9,46,3600},
147 	{ "","SUN0340",0,1538,2,1544,6,72,4200},
148 	{ "","SUN0424",2,1151,2,2500,9,80,4400},
149 	{ "","SUN0535",0,1866,2,2500,7,80,5400},
150 	{ "","SUN0669",5,1614,2,1632,15,54,3600},
151 	{ "","SUN1.0G",5,1703,2,1931,15,80,3597},
152 	{ "","SUN1.05",0,2036,2,2038,14,72,5400},
153 	{ "","SUN1.3G",6,1965,2,3500,17,80,5400},
154 	{ "","SUN2.1G",0,2733,2,3500,19,80,5400},
155 	{ "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
156 };
157 
158 static const struct sun_predefined_drives *
sun_autoconfigure_scsi(void)159 sun_autoconfigure_scsi(void)
160 {
161 	const struct sun_predefined_drives *p = NULL;
162 
163 #ifdef SCSI_IOCTL_GET_IDLUN
164 	unsigned int id[2];
165 	char buffer[2048];
166 	char buffer2[2048];
167 	FILE *pfd;
168 	char *vendor;
169 	char *model;
170 	char *q;
171 	int i;
172 
173 	if (ioctl(dev_fd, SCSI_IOCTL_GET_IDLUN, &id))
174 		return NULL;
175 
176 	sprintf(buffer,
177 		"Host: scsi%u Channel: %02u Id: %02u Lun: %02u\n",
178 		/* This is very wrong (works only if you have one HBA),
179 		   but I haven't found a way how to get hostno
180 		   from the current kernel */
181 		0,
182 		(id[0]>>16) & 0xff,
183 		id[0] & 0xff,
184 		(id[0]>>8) & 0xff
185 	);
186 	pfd = fopen_for_read("/proc/scsi/scsi");
187 	if (!pfd) {
188 		return NULL;
189 	}
190 	while (fgets(buffer2, 2048, pfd)) {
191 		if (strcmp(buffer, buffer2))
192 			continue;
193 		if (!fgets(buffer2, 2048, pfd))
194 			break;
195 		q = strstr(buffer2, "Vendor: ");
196 		if (!q)
197 			break;
198 		q += 8;
199 		vendor = q;
200 		q = strstr(q, " ");
201 		*q++ = '\0';   /* truncate vendor name */
202 		q = strstr(q, "Model: ");
203 		if (!q)
204 			break;
205 		*q = '\0';
206 		q += 7;
207 		model = q;
208 		q = strstr(q, " Rev: ");
209 		if (!q)
210 			break;
211 		*q = '\0';
212 		for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
213 			if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
214 				continue;
215 			if (!strstr(model, sun_drives[i].model))
216 				continue;
217 			printf("Autoconfigure found a %s%s%s\n",
218 					sun_drives[i].vendor,
219 					(*sun_drives[i].vendor) ? " " : "",
220 					sun_drives[i].model);
221 			p = sun_drives + i;
222 			break;
223 		}
224 		break;
225 	}
226 	fclose(pfd);
227 #endif
228 	return p;
229 }
230 
231 static void
create_sunlabel(void)232 create_sunlabel(void)
233 {
234 	struct hd_geometry geometry;
235 	unsigned ndiv;
236 	unsigned char c;
237 	const struct sun_predefined_drives *p = NULL;
238 
239 	printf(msg_building_new_label, "sun disklabel");
240 
241 	sun_other_endian = BB_LITTLE_ENDIAN;
242 	memset(MBRbuffer, 0, sizeof(MBRbuffer));
243 	sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
244 	if (!floppy) {
245 		unsigned i;
246 		puts("Drive type\n"
247 		 "   ?   auto configure\n"
248 		 "   0   custom (with hardware detected defaults)");
249 		for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
250 			printf("   %c   %s%s%s\n",
251 				i + 'a', sun_drives[i].vendor,
252 				(*sun_drives[i].vendor) ? " " : "",
253 				sun_drives[i].model);
254 		}
255 		while (1) {
256 			c = read_nonempty("Select type (? for auto, 0 for custom): ");
257 			if (c == '0') {
258 				break;
259 			}
260 			if (c >= 'a' && c < 'a' + ARRAY_SIZE(sun_drives)) {
261 				p = sun_drives + c - 'a';
262 				break;
263 			}
264 			if (c >= 'A' && c < 'A' + ARRAY_SIZE(sun_drives)) {
265 				p = sun_drives + c - 'A';
266 				break;
267 			}
268 			if (c == '?' && scsi_disk) {
269 				p = sun_autoconfigure_scsi();
270 				if (p)
271 					break;
272 				printf("Autoconfigure failed\n");
273 			}
274 		}
275 	}
276 	if (!p || floppy) {
277 		if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
278 			g_heads = geometry.heads;
279 			g_sectors = geometry.sectors;
280 			g_cylinders = geometry.cylinders;
281 		} else {
282 			g_heads = 0;
283 			g_sectors = 0;
284 			g_cylinders = 0;
285 		}
286 		if (floppy) {
287 			sunlabel->nacyl = 0;
288 			sunlabel->pcylcount = SUN_SSWAP16(g_cylinders);
289 			sunlabel->rspeed = SUN_SSWAP16(300);
290 			sunlabel->ilfact = SUN_SSWAP16(1);
291 			sunlabel->sparecyl = 0;
292 		} else {
293 			g_heads = read_int(1, g_heads, 1024, 0, "Heads");
294 			g_sectors = read_int(1, g_sectors, 1024, 0, "Sectors/track");
295 		if (g_cylinders)
296 			g_cylinders = read_int(1, g_cylinders - 2, 65535, 0, "Cylinders");
297 		else
298 			g_cylinders = read_int(1, 0, 65535, 0, "Cylinders");
299 			sunlabel->nacyl = SUN_SSWAP16(read_int(0, 2, 65535, 0, "Alternate cylinders"));
300 			sunlabel->pcylcount = SUN_SSWAP16(read_int(0, g_cylinders + SUN_SSWAP16(sunlabel->nacyl), 65535, 0, "Physical cylinders"));
301 			sunlabel->rspeed = SUN_SSWAP16(read_int(1, 5400, 100000, 0, "Rotation speed (rpm)"));
302 			sunlabel->ilfact = SUN_SSWAP16(read_int(1, 1, 32, 0, "Interleave factor"));
303 			sunlabel->sparecyl = SUN_SSWAP16(read_int(0, 0, g_sectors, 0, "Extra sectors per cylinder"));
304 		}
305 	} else {
306 		sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
307 		sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
308 		sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
309 		sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
310 		sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
311 		sunlabel->nsect = SUN_SSWAP16(p->nsect);
312 		sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
313 		sunlabel->ilfact = SUN_SSWAP16(1);
314 		g_cylinders = p->ncyl;
315 		g_heads = p->ntrks;
316 		g_sectors = p->nsect;
317 		puts("You may change all the disk params from the x menu");
318 	}
319 
320 	snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
321 		"%s%s%s cyl %u alt %u hd %u sec %u",
322 		p ? p->vendor : "", (p && *p->vendor) ? " " : "",
323 		p ? p->model : (floppy ? "3,5\" floppy" : "Linux custom"),
324 		g_cylinders, SUN_SSWAP16(sunlabel->nacyl), g_heads, g_sectors);
325 
326 	sunlabel->ntrks = SUN_SSWAP16(g_heads);
327 	sunlabel->nsect = SUN_SSWAP16(g_sectors);
328 	sunlabel->ncyl = SUN_SSWAP16(g_cylinders);
329 	if (floppy)
330 		set_sun_partition(0, 0, g_cylinders * g_heads * g_sectors, LINUX_NATIVE);
331 	else {
332 		if (g_cylinders * g_heads * g_sectors >= 150 * 2048) {
333 			ndiv = g_cylinders - (50 * 2048 / (g_heads * g_sectors)); /* 50M swap */
334 		} else
335 			ndiv = g_cylinders * 2 / 3;
336 		set_sun_partition(0, 0, ndiv * g_heads * g_sectors, LINUX_NATIVE);
337 		set_sun_partition(1, ndiv * g_heads * g_sectors, g_cylinders * g_heads * g_sectors, LINUX_SWAP);
338 		sunlabel->infos[1].flags |= 0x01; /* Not mountable */
339 	}
340 	set_sun_partition(2, 0, g_cylinders * g_heads * g_sectors, SUN_WHOLE_DISK);
341 	{
342 		unsigned short *ush = (unsigned short *)sunlabel;
343 		unsigned short csum = 0;
344 		while (ush < (unsigned short *)(&sunlabel->csum))
345 			csum ^= *ush++;
346 		sunlabel->csum = csum;
347 	}
348 
349 	set_all_unchanged();
350 	set_changed(0);
351 	check_sun_label();
352 	get_boot(CREATE_EMPTY_SUN);
353 }
354 
355 static void
toggle_sunflags(int i,unsigned char mask)356 toggle_sunflags(int i, unsigned char mask)
357 {
358 	if (sunlabel->infos[i].flags & mask)
359 		sunlabel->infos[i].flags &= ~mask;
360 	else
361 		sunlabel->infos[i].flags |= mask;
362 	set_changed(i);
363 }
364 
365 static void
fetch_sun(unsigned * starts,unsigned * lens,unsigned * start,unsigned * stop)366 fetch_sun(unsigned *starts, unsigned *lens, unsigned *start, unsigned *stop)
367 {
368 	int i, continuous = 1;
369 
370 	*start = 0;
371 	*stop = g_cylinders * g_heads * g_sectors;
372 	for (i = 0; i < g_partitions; i++) {
373 		if (sunlabel->partitions[i].num_sectors
374 		 && sunlabel->infos[i].id
375 		 && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
376 			starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
377 			lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
378 			if (continuous) {
379 				if (starts[i] == *start)
380 					*start += lens[i];
381 				else if (starts[i] + lens[i] >= *stop)
382 					*stop = starts[i];
383 				else
384 					continuous = 0;
385 					/* There will be probably more gaps
386 					  than one, so lets check afterwards */
387 			}
388 		} else {
389 			starts[i] = 0;
390 			lens[i] = 0;
391 		}
392 	}
393 }
394 
395 static unsigned *verify_sun_starts;
396 
397 static int
verify_sun_cmp(int * a,int * b)398 verify_sun_cmp(int *a, int *b)
399 {
400 	if (*a == -1) return 1;
401 	if (*b == -1) return -1;
402 	if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
403 	return -1;
404 }
405 
406 static void
verify_sun(void)407 verify_sun(void)
408 {
409 	unsigned starts[8], lens[8], start, stop;
410 	int i,j,k,starto,endo;
411 	int array[8];
412 
413 	verify_sun_starts = starts;
414 	fetch_sun(starts, lens, &start, &stop);
415 	for (k = 0; k < 7; k++) {
416 		for (i = 0; i < 8; i++) {
417 			if (k && (lens[i] % (g_heads * g_sectors))) {
418 				printf("Partition %u doesn't end on cylinder boundary\n", i+1);
419 			}
420 			if (lens[i]) {
421 				for (j = 0; j < i; j++)
422 					if (lens[j]) {
423 						if (starts[j] == starts[i]+lens[i]) {
424 							starts[j] = starts[i]; lens[j] += lens[i];
425 							lens[i] = 0;
426 						} else if (starts[i] == starts[j]+lens[j]){
427 							lens[j] += lens[i];
428 							lens[i] = 0;
429 						} else if (!k) {
430 							if (starts[i] < starts[j]+lens[j]
431 							 && starts[j] < starts[i]+lens[i]) {
432 								starto = starts[i];
433 								if (starts[j] > starto)
434 									starto = starts[j];
435 								endo = starts[i]+lens[i];
436 								if (starts[j]+lens[j] < endo)
437 									endo = starts[j]+lens[j];
438 								printf("Partition %u overlaps with others in "
439 									"sectors %u-%u\n", i+1, starto, endo);
440 							}
441 						}
442 					}
443 			}
444 		}
445 	}
446 	for (i = 0; i < 8; i++) {
447 		if (lens[i])
448 			array[i] = i;
449 		else
450 			array[i] = -1;
451 	}
452 	qsort(array, ARRAY_SIZE(array), sizeof(array[0]),
453 		(int (*)(const void *,const void *)) verify_sun_cmp);
454 	if (array[0] == -1) {
455 		printf("No partitions defined\n");
456 		return;
457 	}
458 	stop = g_cylinders * g_heads * g_sectors;
459 	if (starts[array[0]])
460 		printf("Unused gap - sectors %u-%u\n", 0, starts[array[0]]);
461 	for (i = 0; i < 7 && array[i+1] != -1; i++) {
462 		printf("Unused gap - sectors %u-%u\n", starts[array[i]]+lens[array[i]], starts[array[i+1]]);
463 	}
464 	start = starts[array[i]] + lens[array[i]];
465 	if (start < stop)
466 		printf("Unused gap - sectors %u-%u\n", start, stop);
467 }
468 
469 static void
add_sun_partition(int n,int sys)470 add_sun_partition(int n, int sys)
471 {
472 	unsigned start, stop, stop2;
473 	unsigned starts[8], lens[8];
474 	int whole_disk = 0;
475 
476 	char mesg[256];
477 	int i, first, last;
478 
479 	if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
480 		printf(msg_part_already_defined, n + 1);
481 		return;
482 	}
483 
484 	fetch_sun(starts, lens, &start, &stop);
485 	if (stop <= start) {
486 		if (n == 2)
487 			whole_disk = 1;
488 		else {
489 			printf("Other partitions already cover the whole disk.\n"
490 				"Delete/shrink them before retry.\n");
491 			return;
492 		}
493 	}
494 	snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
495 	while (1) {
496 		if (whole_disk)
497 			first = read_int(0, 0, 0, 0, mesg);
498 		else
499 			first = read_int(scround(start), scround(stop)+1,
500 					 scround(stop), 0, mesg);
501 		if (display_in_cyl_units) {
502 			first *= units_per_sector;
503 		} else {
504 			/* Starting sector has to be properly aligned */
505 			first = (first + g_heads * g_sectors - 1) /
506 				(g_heads * g_sectors);
507 			first *= g_heads * g_sectors;
508 		}
509 		if (n == 2 && first != 0)
510 			printf("\
511 It is highly recommended that the third partition covers the whole disk\n\
512 and is of type 'Whole disk'\n");
513 		/* ewt asks to add: "don't start a partition at cyl 0"
514 		   However, edmundo@rano.demon.co.uk writes:
515 		   "In addition to having a Sun partition table, to be able to
516 		   boot from the disc, the first partition, /dev/sdX1, must
517 		   start at cylinder 0. This means that /dev/sdX1 contains
518 		   the partition table and the boot block, as these are the
519 		   first two sectors of the disc. Therefore you must be
520 		   careful what you use /dev/sdX1 for. In particular, you must
521 		   not use a partition starting at cylinder 0 for Linux swap,
522 		   as that would overwrite the partition table and the boot
523 		   block. You may, however, use such a partition for a UFS
524 		   or EXT2 file system, as these file systems leave the first
525 		   1024 bytes undisturbed. */
526 		/* On the other hand, one should not use partitions
527 		   starting at block 0 in an md, or the label will
528 		   be trashed. */
529 		for (i = 0; i < g_partitions; i++)
530 			if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
531 				break;
532 		if (i < g_partitions && !whole_disk) {
533 			if (n == 2 && !first) {
534 				whole_disk = 1;
535 				break;
536 			}
537 			printf("Sector %u is already allocated\n", first);
538 		} else
539 			break;
540 	}
541 	stop = g_cylinders * g_heads * g_sectors;
542 	stop2 = stop;
543 	for (i = 0; i < g_partitions; i++) {
544 		if (starts[i] > first && starts[i] < stop)
545 			stop = starts[i];
546 	}
547 	snprintf(mesg, sizeof(mesg),
548 		"Last %s or +size or +sizeM or +sizeK",
549 		str_units(SINGULAR));
550 	if (whole_disk)
551 		last = read_int(scround(stop2), scround(stop2), scround(stop2),
552 				0, mesg);
553 	else if (n == 2 && !first)
554 		last = read_int(scround(first), scround(stop2), scround(stop2),
555 				scround(first), mesg);
556 	else
557 		last = read_int(scround(first), scround(stop), scround(stop),
558 				scround(first), mesg);
559 	if (display_in_cyl_units)
560 		last *= units_per_sector;
561 	if (n == 2 && !first) {
562 		if (last >= stop2) {
563 			whole_disk = 1;
564 			last = stop2;
565 		} else if (last > stop) {
566 			printf(
567 "You haven't covered the whole disk with the 3rd partition,\n"
568 "but your value %u %s covers some other partition.\n"
569 "Your entry has been changed to %u %s\n",
570 				scround(last), str_units(SINGULAR),
571 				scround(stop), str_units(SINGULAR));
572 			last = stop;
573 		}
574 	} else if (!whole_disk && last > stop)
575 		last = stop;
576 
577 	if (whole_disk)
578 		sys = SUN_WHOLE_DISK;
579 	set_sun_partition(n, first, last, sys);
580 }
581 
582 static void
sun_delete_partition(int i)583 sun_delete_partition(int i)
584 {
585 	unsigned int nsec;
586 
587 	if (i == 2
588 	 && sunlabel->infos[i].id == SUN_WHOLE_DISK
589 	 && !sunlabel->partitions[i].start_cylinder
590 	 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == g_heads * g_sectors * g_cylinders)
591 		printf("If you want to maintain SunOS/Solaris compatibility, "
592 			"consider leaving this\n"
593 			"partition as Whole disk (5), starting at 0, with %u "
594 			"sectors\n", nsec);
595 	sunlabel->infos[i].id = 0;
596 	sunlabel->partitions[i].num_sectors = 0;
597 }
598 
599 static void
sun_change_sysid(int i,int sys)600 sun_change_sysid(int i, int sys)
601 {
602 	if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
603 		read_maybe_empty(
604 			"It is highly recommended that the partition at offset 0\n"
605 			"is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
606 			"there may destroy your partition table and bootblock.\n"
607 			"Type YES if you're very sure you would like that partition\n"
608 			"tagged with 82 (Linux swap): ");
609 		if (strcmp (line_ptr, "YES\n"))
610 			return;
611 	}
612 	switch (sys) {
613 	case SUNOS_SWAP:
614 	case LINUX_SWAP:
615 		/* swaps are not mountable by default */
616 		sunlabel->infos[i].flags |= 0x01;
617 		break;
618 	default:
619 		/* assume other types are mountable;
620 		   user can change it anyway */
621 		sunlabel->infos[i].flags &= ~0x01;
622 		break;
623 	}
624 	sunlabel->infos[i].id = sys;
625 }
626 
627 static void
sun_list_table(int xtra)628 sun_list_table(int xtra)
629 {
630 	int i, w;
631 
632 	w = strlen(disk_device);
633 	if (xtra)
634 		printf(
635 		"\nDisk %s (Sun disk label): %u heads, %u sectors, %u rpm\n"
636 		"%u cylinders, %u alternate cylinders, %u physical cylinders\n"
637 		"%u extra sects/cyl, interleave %u:1\n"
638 		"%s\n"
639 		"Units = %s of %u * 512 bytes\n\n",
640 			disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed),
641 			g_cylinders, SUN_SSWAP16(sunlabel->nacyl),
642 			SUN_SSWAP16(sunlabel->pcylcount),
643 			SUN_SSWAP16(sunlabel->sparecyl),
644 			SUN_SSWAP16(sunlabel->ilfact),
645 			(char *)sunlabel,
646 			str_units(PLURAL), units_per_sector);
647 	else
648 		printf(
649 	"\nDisk %s (Sun disk label): %u heads, %u sectors, %u cylinders\n"
650 	"Units = %s of %u * 512 bytes\n\n",
651 			disk_device, g_heads, g_sectors, g_cylinders,
652 			str_units(PLURAL), units_per_sector);
653 
654 	printf("%*s Flag    Start       End    Blocks   Id  System\n",
655 		w + 1, "Device");
656 	for (i = 0; i < g_partitions; i++) {
657 		if (sunlabel->partitions[i].num_sectors) {
658 			uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
659 			uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
660 			printf("%s %c%c %9lu %9lu %9lu%c  %2x  %s\n",
661 				partname(disk_device, i+1, w),                  /* device */
662 				(sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',  /* flags */
663 				(sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
664 				(long) scround(start),                          /* start */
665 				(long) scround(start+len),                      /* end */
666 				(long) len / 2, len & 1 ? '+' : ' ',            /* odd flag on end */
667 				sunlabel->infos[i].id,                          /* type id */
668 				partition_type(sunlabel->infos[i].id));         /* type name */
669 		}
670 	}
671 }
672 
673 #if ENABLE_FEATURE_FDISK_ADVANCED
674 
675 static void
sun_set_alt_cyl(void)676 sun_set_alt_cyl(void)
677 {
678 	sunlabel->nacyl =
679 		SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
680 				"Number of alternate cylinders"));
681 }
682 
683 static void
sun_set_ncyl(int cyl)684 sun_set_ncyl(int cyl)
685 {
686 	sunlabel->ncyl = SUN_SSWAP16(cyl);
687 }
688 
689 static void
sun_set_xcyl(void)690 sun_set_xcyl(void)
691 {
692 	sunlabel->sparecyl =
693 		SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), g_sectors, 0,
694 				"Extra sectors per cylinder"));
695 }
696 
697 static void
sun_set_ilfact(void)698 sun_set_ilfact(void)
699 {
700 	sunlabel->ilfact =
701 		SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
702 				"Interleave factor"));
703 }
704 
705 static void
sun_set_rspeed(void)706 sun_set_rspeed(void)
707 {
708 	sunlabel->rspeed =
709 		SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
710 				"Rotation speed (rpm)"));
711 }
712 
713 static void
sun_set_pcylcount(void)714 sun_set_pcylcount(void)
715 {
716 	sunlabel->pcylcount =
717 		SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
718 				"Number of physical cylinders"));
719 }
720 #endif /* FEATURE_FDISK_ADVANCED */
721 
722 static void
sun_write_table(void)723 sun_write_table(void)
724 {
725 	unsigned short *ush = (unsigned short *)sunlabel;
726 	unsigned short csum = 0;
727 
728 	while (ush < (unsigned short *)(&sunlabel->csum))
729 		csum ^= *ush++;
730 	sunlabel->csum = csum;
731 	write_sector(0, sunlabel);
732 }
733 #endif /* SUN_LABEL */
734