blkid: add type display for btrfs
[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         get_boot(CREATE_EMPTY_SUN);
352 }
353
354 static void
355 toggle_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
364 static void
365 fetch_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
394 static unsigned *verify_sun_starts;
395
396 static int
397 verify_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
405 static void
406 verify_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
468 static void
469 add_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("\
507 It is highly recommended that the third partition covers the whole disk\n\
508 and 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
578 static void
579 sun_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
595 static void
596 sun_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
623 static void
624 sun_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
671 static void
672 sun_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
679 static void
680 sun_set_ncyl(int cyl)
681 {
682         sunlabel->ncyl = SUN_SSWAP16(cyl);
683 }
684
685 static void
686 sun_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
693 static void
694 sun_set_ilfact(void)
695 {
696         sunlabel->ilfact =
697                 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
698                                 "Interleave factor"));
699 }
700
701 static void
702 sun_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
709 static void
710 sun_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
718 static void
719 sun_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 */