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