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