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