Bump to version 1.22.1
[platform/upstream/busybox.git] / util-linux / fdisk_sun.c
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
684 sun_set_ncyl(int cyl)
685 {
686         sunlabel->ncyl = SUN_SSWAP16(cyl);
687 }
688
689 static 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
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
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
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
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 */