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