• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/busybox/util-linux/
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 tarball for details.
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
30static smallint sun_other_endian;
31static smallint scsi_disk;
32static 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
41static void
42guess_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
64static 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
83static void
84set_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
94static int
95check_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
126static 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
158static const struct sun_predefined_drives *
159sun_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
231static void
232create_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	get_boot(CREATE_EMPTY_SUN);
352}
353
354static void
355toggle_sunflags(int i, unsigned char mask)
356{
357	if (sunlabel->infos[i].flags & mask)
358		sunlabel->infos[i].flags &= ~mask;
359	else
360		sunlabel->infos[i].flags |= mask;
361	set_changed(i);
362}
363
364static void
365fetch_sun(unsigned *starts, unsigned *lens, unsigned *start, unsigned *stop)
366{
367	int i, continuous = 1;
368
369	*start = 0;
370	*stop = g_cylinders * g_heads * g_sectors;
371	for (i = 0; i < g_partitions; i++) {
372		if (sunlabel->partitions[i].num_sectors
373		 && sunlabel->infos[i].id
374		 && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
375			starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
376			lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
377			if (continuous) {
378				if (starts[i] == *start)
379					*start += lens[i];
380				else if (starts[i] + lens[i] >= *stop)
381					*stop = starts[i];
382				else
383					continuous = 0;
384					/* There will be probably more gaps
385					  than one, so lets check afterwards */
386			}
387		} else {
388			starts[i] = 0;
389			lens[i] = 0;
390		}
391	}
392}
393
394static unsigned *verify_sun_starts;
395
396static int
397verify_sun_cmp(int *a, int *b)
398{
399	if (*a == -1) return 1;
400	if (*b == -1) return -1;
401	if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
402	return -1;
403}
404
405static void
406verify_sun(void)
407{
408	unsigned starts[8], lens[8], start, stop;
409	int i,j,k,starto,endo;
410	int array[8];
411
412	verify_sun_starts = starts;
413	fetch_sun(starts, lens, &start, &stop);
414	for (k = 0; k < 7; k++) {
415		for (i = 0; i < 8; i++) {
416			if (k && (lens[i] % (g_heads * g_sectors))) {
417				printf("Partition %u doesn't end on cylinder boundary\n", i+1);
418			}
419			if (lens[i]) {
420				for (j = 0; j < i; j++)
421					if (lens[j]) {
422						if (starts[j] == starts[i]+lens[i]) {
423							starts[j] = starts[i]; lens[j] += lens[i];
424							lens[i] = 0;
425						} else if (starts[i] == starts[j]+lens[j]){
426							lens[j] += lens[i];
427							lens[i] = 0;
428						} else if (!k) {
429							if (starts[i] < starts[j]+lens[j]
430							 && starts[j] < starts[i]+lens[i]) {
431								starto = starts[i];
432								if (starts[j] > starto)
433									starto = starts[j];
434								endo = starts[i]+lens[i];
435								if (starts[j]+lens[j] < endo)
436									endo = starts[j]+lens[j];
437								printf("Partition %u overlaps with others in "
438									"sectors %u-%u\n", i+1, starto, endo);
439							}
440						}
441					}
442			}
443		}
444	}
445	for (i = 0; i < 8; i++) {
446		if (lens[i])
447			array[i] = i;
448		else
449			array[i] = -1;
450	}
451	qsort(array, ARRAY_SIZE(array), sizeof(array[0]),
452		(int (*)(const void *,const void *)) verify_sun_cmp);
453	if (array[0] == -1) {
454		printf("No partitions defined\n");
455		return;
456	}
457	stop = g_cylinders * g_heads * g_sectors;
458	if (starts[array[0]])
459		printf("Unused gap - sectors %u-%u\n", 0, starts[array[0]]);
460	for (i = 0; i < 7 && array[i+1] != -1; i++) {
461		printf("Unused gap - sectors %u-%u\n", starts[array[i]]+lens[array[i]], starts[array[i+1]]);
462	}
463	start = starts[array[i]] + lens[array[i]];
464	if (start < stop)
465		printf("Unused gap - sectors %u-%u\n", start, stop);
466}
467
468static void
469add_sun_partition(int n, int sys)
470{
471	unsigned start, stop, stop2;
472	unsigned starts[8], lens[8];
473	int whole_disk = 0;
474
475	char mesg[256];
476	int i, first, last;
477
478	if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
479		printf(msg_part_already_defined, n + 1);
480		return;
481	}
482
483	fetch_sun(starts, lens, &start, &stop);
484	if (stop <= start) {
485		if (n == 2)
486			whole_disk = 1;
487		else {
488			printf("Other partitions already cover the whole disk.\n"
489				"Delete/shrink them before retry.\n");
490			return;
491		}
492	}
493	snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
494	while (1) {
495		if (whole_disk)
496			first = read_int(0, 0, 0, 0, mesg);
497		else
498			first = read_int(scround(start), scround(stop)+1,
499					 scround(stop), 0, mesg);
500		if (display_in_cyl_units)
501			first *= units_per_sector;
502		else
503			/* Starting sector has to be properly aligned */
504			first = (first + g_heads * g_sectors - 1) / (g_heads * g_sectors);
505		if (n == 2 && first != 0)
506			printf("\
507It is highly recommended that the third partition covers the whole disk\n\
508and is of type 'Whole disk'\n");
509		/* ewt asks to add: "don't start a partition at cyl 0"
510		   However, edmundo@rano.demon.co.uk writes:
511		   "In addition to having a Sun partition table, to be able to
512		   boot from the disc, the first partition, /dev/sdX1, must
513		   start at cylinder 0. This means that /dev/sdX1 contains
514		   the partition table and the boot block, as these are the
515		   first two sectors of the disc. Therefore you must be
516		   careful what you use /dev/sdX1 for. In particular, you must
517		   not use a partition starting at cylinder 0 for Linux swap,
518		   as that would overwrite the partition table and the boot
519		   block. You may, however, use such a partition for a UFS
520		   or EXT2 file system, as these file systems leave the first
521		   1024 bytes undisturbed. */
522		/* On the other hand, one should not use partitions
523		   starting at block 0 in an md, or the label will
524		   be trashed. */
525		for (i = 0; i < g_partitions; i++)
526			if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
527				break;
528		if (i < g_partitions && !whole_disk) {
529			if (n == 2 && !first) {
530				whole_disk = 1;
531				break;
532			}
533			printf("Sector %u is already allocated\n", first);
534		} else
535			break;
536	}
537	stop = g_cylinders * g_heads * g_sectors;
538	stop2 = stop;
539	for (i = 0; i < g_partitions; i++) {
540		if (starts[i] > first && starts[i] < stop)
541			stop = starts[i];
542	}
543	snprintf(mesg, sizeof(mesg),
544		"Last %s or +size or +sizeM or +sizeK",
545		str_units(SINGULAR));
546	if (whole_disk)
547		last = read_int(scround(stop2), scround(stop2), scround(stop2),
548				0, mesg);
549	else if (n == 2 && !first)
550		last = read_int(scround(first), scround(stop2), scround(stop2),
551				scround(first), mesg);
552	else
553		last = read_int(scround(first), scround(stop), scround(stop),
554				scround(first), mesg);
555	if (display_in_cyl_units)
556		last *= units_per_sector;
557	if (n == 2 && !first) {
558		if (last >= stop2) {
559			whole_disk = 1;
560			last = stop2;
561		} else if (last > stop) {
562			printf(
563"You haven't covered the whole disk with the 3rd partition,\n"
564"but your value %u %s covers some other partition.\n"
565"Your entry has been changed to %u %s\n",
566				scround(last), str_units(SINGULAR),
567				scround(stop), str_units(SINGULAR));
568			last = stop;
569		}
570	} else if (!whole_disk && last > stop)
571		last = stop;
572
573	if (whole_disk)
574		sys = SUN_WHOLE_DISK;
575	set_sun_partition(n, first, last, sys);
576}
577
578static void
579sun_delete_partition(int i)
580{
581	unsigned int nsec;
582
583	if (i == 2
584	 && sunlabel->infos[i].id == SUN_WHOLE_DISK
585	 && !sunlabel->partitions[i].start_cylinder
586	 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == g_heads * g_sectors * g_cylinders)
587		printf("If you want to maintain SunOS/Solaris compatibility, "
588			"consider leaving this\n"
589			"partition as Whole disk (5), starting at 0, with %u "
590			"sectors\n", nsec);
591	sunlabel->infos[i].id = 0;
592	sunlabel->partitions[i].num_sectors = 0;
593}
594
595static void
596sun_change_sysid(int i, int sys)
597{
598	if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
599		read_maybe_empty(
600			"It is highly recommended that the partition at offset 0\n"
601			"is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
602			"there may destroy your partition table and bootblock.\n"
603			"Type YES if you're very sure you would like that partition\n"
604			"tagged with 82 (Linux swap): ");
605		if (strcmp (line_ptr, "YES\n"))
606			return;
607	}
608	switch (sys) {
609	case SUNOS_SWAP:
610	case LINUX_SWAP:
611		/* swaps are not mountable by default */
612		sunlabel->infos[i].flags |= 0x01;
613		break;
614	default:
615		/* assume other types are mountable;
616		   user can change it anyway */
617		sunlabel->infos[i].flags &= ~0x01;
618		break;
619	}
620	sunlabel->infos[i].id = sys;
621}
622
623static void
624sun_list_table(int xtra)
625{
626	int i, w;
627
628	w = strlen(disk_device);
629	if (xtra)
630		printf(
631		"\nDisk %s (Sun disk label): %u heads, %u sectors, %u rpm\n"
632		"%u cylinders, %u alternate cylinders, %u physical cylinders\n"
633		"%u extra sects/cyl, interleave %u:1\n"
634		"%s\n"
635		"Units = %s of %u * 512 bytes\n\n",
636			disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed),
637			g_cylinders, SUN_SSWAP16(sunlabel->nacyl),
638			SUN_SSWAP16(sunlabel->pcylcount),
639			SUN_SSWAP16(sunlabel->sparecyl),
640			SUN_SSWAP16(sunlabel->ilfact),
641			(char *)sunlabel,
642			str_units(PLURAL), units_per_sector);
643	else
644		printf(
645	"\nDisk %s (Sun disk label): %u heads, %u sectors, %u cylinders\n"
646	"Units = %s of %u * 512 bytes\n\n",
647			disk_device, g_heads, g_sectors, g_cylinders,
648			str_units(PLURAL), units_per_sector);
649
650	printf("%*s Flag    Start       End    Blocks   Id  System\n",
651		w + 1, "Device");
652	for (i = 0; i < g_partitions; i++) {
653		if (sunlabel->partitions[i].num_sectors) {
654			uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
655			uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
656			printf("%s %c%c %9lu %9lu %9lu%c  %2x  %s\n",
657				partname(disk_device, i+1, w),			/* device */
658				(sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',  /* flags */
659				(sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
660				(long) scround(start),                          /* start */
661				(long) scround(start+len),                      /* end */
662				(long) len / 2, len & 1 ? '+' : ' ',            /* odd flag on end */
663				sunlabel->infos[i].id,                          /* type id */
664				partition_type(sunlabel->infos[i].id));         /* type name */
665		}
666	}
667}
668
669#if ENABLE_FEATURE_FDISK_ADVANCED
670
671static void
672sun_set_alt_cyl(void)
673{
674	sunlabel->nacyl =
675		SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
676				"Number of alternate cylinders"));
677}
678
679static void
680sun_set_ncyl(int cyl)
681{
682	sunlabel->ncyl = SUN_SSWAP16(cyl);
683}
684
685static void
686sun_set_xcyl(void)
687{
688	sunlabel->sparecyl =
689		SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), g_sectors, 0,
690				"Extra sectors per cylinder"));
691}
692
693static void
694sun_set_ilfact(void)
695{
696	sunlabel->ilfact =
697		SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
698				"Interleave factor"));
699}
700
701static void
702sun_set_rspeed(void)
703{
704	sunlabel->rspeed =
705		SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
706				"Rotation speed (rpm)"));
707}
708
709static void
710sun_set_pcylcount(void)
711{
712	sunlabel->pcylcount =
713		SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
714				"Number of physical cylinders"));
715}
716#endif /* FEATURE_FDISK_ADVANCED */
717
718static void
719sun_write_table(void)
720{
721	unsigned short *ush = (unsigned short *)sunlabel;
722	unsigned short csum = 0;
723
724	while (ush < (unsigned short *)(&sunlabel->csum))
725		csum ^= *ush++;
726	sunlabel->csum = csum;
727	write_sector(0, sunlabel);
728}
729#endif /* SUN_LABEL */
730