hust test: complain if busybox binary can't be found
[oweals/busybox.git] / util-linux / fdisk_sun.c
1 /*
2  * fdisk_sun.c
3  *
4  * I think this is mostly, or entirely, due to
5  *      Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
6  *
7  * Merged with fdisk for other architectures, aeb, June 1998.
8  *
9  * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
10  *      Internationalization
11  *
12  * Licensed under GPLv2, see file LICENSE in this tarball for details.
13  */
14
15 #if ENABLE_FEATURE_SUN_LABEL
16
17 #define SUNOS_SWAP 3
18 #define SUN_WHOLE_DISK 5
19
20 #define SUN_LABEL_MAGIC          0xDABE
21 #define SUN_LABEL_MAGIC_SWAPPED  0xBEDA
22 #define SUN_SSWAP16(x) (sun_other_endian ? fdisk_swap16(x) : (uint16_t)(x))
23 #define SUN_SSWAP32(x) (sun_other_endian ? fdisk_swap32(x) : (uint32_t)(x))
24
25 /* Copied from linux/major.h */
26 #define FLOPPY_MAJOR    2
27
28 #define SCSI_IOCTL_GET_IDLUN 0x5382
29
30 static int sun_other_endian;
31 static int scsi_disk;
32 static int floppy;
33
34 #ifndef IDE0_MAJOR
35 #define IDE0_MAJOR 3
36 #endif
37 #ifndef IDE1_MAJOR
38 #define IDE1_MAJOR 22
39 #endif
40
41 static void
42 guess_device_type(void)
43 {
44         struct stat bootstat;
45
46         if (fstat(dev_fd, &bootstat) < 0) {
47                 scsi_disk = 0;
48                 floppy = 0;
49         } else if (S_ISBLK(bootstat.st_mode)
50                 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
51                     major(bootstat.st_rdev) == IDE1_MAJOR)) {
52                 scsi_disk = 0;
53                 floppy = 0;
54         } else if (S_ISBLK(bootstat.st_mode)
55                 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
56                 scsi_disk = 0;
57                 floppy = 1;
58         } else {
59                 scsi_disk = 1;
60                 floppy = 0;
61         }
62 }
63
64 static const char *const sun_sys_types[] = {
65         "\x00" "Empty"       , /* 0            */
66         "\x01" "Boot"        , /* 1            */
67         "\x02" "SunOS root"  , /* 2            */
68         "\x03" "SunOS swap"  , /* SUNOS_SWAP   */
69         "\x04" "SunOS usr"   , /* 4            */
70         "\x05" "Whole disk"  , /* SUN_WHOLE_DISK   */
71         "\x06" "SunOS stand" , /* 6            */
72         "\x07" "SunOS var"   , /* 7            */
73         "\x08" "SunOS home"  , /* 8            */
74         "\x82" "Linux swap"  , /* LINUX_SWAP   */
75         "\x83" "Linux native", /* LINUX_NATIVE */
76         "\x8e" "Linux LVM"   , /* 0x8e         */
77 /* New (2.2.x) raid partition with autodetect using persistent superblock */
78         "\xfd" "Linux raid autodetect", /* 0xfd         */
79         NULL
80 };
81
82
83 static void
84 set_sun_partition(int i, uint start, uint stop, int sysid)
85 {
86         sunlabel->infos[i].id = sysid;
87         sunlabel->partitions[i].start_cylinder =
88                 SUN_SSWAP32(start / (g_heads * g_sectors));
89         sunlabel->partitions[i].num_sectors =
90                 SUN_SSWAP32(stop - start);
91         set_changed(i);
92 }
93
94 static int
95 check_sun_label(void)
96 {
97         unsigned short *ush;
98         int csum;
99
100         if (sunlabel->magic != SUN_LABEL_MAGIC
101          && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
102                 current_label_type = LABEL_DOS;
103                 sun_other_endian = 0;
104                 return 0;
105         }
106         sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
107         ush = ((unsigned short *) (sunlabel + 1)) - 1;
108         for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
109         if (csum) {
110                 printf("Detected sun disklabel with wrong checksum.\n"
111 "Probably you'll have to set all the values,\n"
112 "e.g. heads, sectors, cylinders and partitions\n"
113 "or force a fresh label (s command in main menu)\n");
114         } else {
115                 g_heads = SUN_SSWAP16(sunlabel->ntrks);
116                 g_cylinders = SUN_SSWAP16(sunlabel->ncyl);
117                 g_sectors = SUN_SSWAP16(sunlabel->nsect);
118         }
119         update_units();
120         current_label_type = LABEL_SUN;
121         g_partitions = 8;
122         return 1;
123 }
124
125 static const struct sun_predefined_drives {
126         const char *vendor;
127         const char *model;
128         unsigned short sparecyl;
129         unsigned short ncyl;
130         unsigned short nacyl;
131         unsigned short pcylcount;
132         unsigned short ntrks;
133         unsigned short nsect;
134         unsigned short rspeed;
135 } sun_drives[] = {
136         { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
137         { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
138         { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
139         { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
140         { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
141         { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
142         { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
143         { "","SUN0104",1,974,2,1019,6,35,3662},
144         { "","SUN0207",4,1254,2,1272,9,36,3600},
145         { "","SUN0327",3,1545,2,1549,9,46,3600},
146         { "","SUN0340",0,1538,2,1544,6,72,4200},
147         { "","SUN0424",2,1151,2,2500,9,80,4400},
148         { "","SUN0535",0,1866,2,2500,7,80,5400},
149         { "","SUN0669",5,1614,2,1632,15,54,3600},
150         { "","SUN1.0G",5,1703,2,1931,15,80,3597},
151         { "","SUN1.05",0,2036,2,2038,14,72,5400},
152         { "","SUN1.3G",6,1965,2,3500,17,80,5400},
153         { "","SUN2.1G",0,2733,2,3500,19,80,5400},
154         { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
155 };
156
157 static const struct sun_predefined_drives *
158 sun_autoconfigure_scsi(void)
159 {
160         const struct sun_predefined_drives *p = NULL;
161
162 #ifdef SCSI_IOCTL_GET_IDLUN
163         unsigned int id[2];
164         char buffer[2048];
165         char buffer2[2048];
166         FILE *pfd;
167         char *vendor;
168         char *model;
169         char *q;
170         int i;
171
172         if (ioctl(dev_fd, SCSI_IOCTL_GET_IDLUN, &id))
173                 return NULL;
174
175         sprintf(buffer,
176                 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
177                 /* This is very wrong (works only if you have one HBA),
178                    but I haven't found a way how to get hostno
179                    from the current kernel */
180                 0,
181                 (id[0]>>16) & 0xff,
182                 id[0] & 0xff,
183                 (id[0]>>8) & 0xff
184         );
185         pfd = fopen_for_read("/proc/scsi/scsi");
186         if (!pfd) {
187                 return NULL;
188         }
189         while (fgets(buffer2, 2048, pfd)) {
190                 if (strcmp(buffer, buffer2))
191                         continue;
192                 if (!fgets(buffer2, 2048, pfd))
193                         break;
194                 q = strstr(buffer2, "Vendor: ");
195                 if (!q)
196                         break;
197                 q += 8;
198                 vendor = q;
199                 q = strstr(q, " ");
200                 *q++ = '\0';   /* truncate vendor name */
201                 q = strstr(q, "Model: ");
202                 if (!q)
203                         break;
204                 *q = '\0';
205                 q += 7;
206                 model = q;
207                 q = strstr(q, " Rev: ");
208                 if (!q)
209                         break;
210                 *q = '\0';
211                 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
212                         if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
213                                 continue;
214                         if (!strstr(model, sun_drives[i].model))
215                                 continue;
216                         printf("Autoconfigure found a %s%s%s\n",
217                                         sun_drives[i].vendor,
218                                         (*sun_drives[i].vendor) ? " " : "",
219                                         sun_drives[i].model);
220                         p = sun_drives + i;
221                         break;
222                 }
223                 break;
224         }
225         fclose(pfd);
226 #endif
227         return p;
228 }
229
230 static void
231 create_sunlabel(void)
232 {
233         struct hd_geometry geometry;
234         unsigned ndiv;
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                 unsigned i;
245                 puts("Drive type\n"
246                  "   ?   auto configure\n"
247                  "   0   custom (with hardware detected defaults)");
248                 for (i = 0; i < ARRAY_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 == '0') {
257                                 break;
258                         }
259                         if (c >= 'a' && c < 'a' + ARRAY_SIZE(sun_drives)) {
260                                 p = sun_drives + c - 'a';
261                                 break;
262                         }
263                         if (c >= 'A' && c < 'A' + ARRAY_SIZE(sun_drives)) {
264                                 p = sun_drives + c - 'A';
265                                 break;
266                         }
267                         if (c == '?' && scsi_disk) {
268                                 p = sun_autoconfigure_scsi();
269                                 if (p)
270                                         break;
271                                 printf("Autoconfigure failed\n");
272                         }
273                 }
274         }
275         if (!p || floppy) {
276                 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
277                         g_heads = geometry.heads;
278                         g_sectors = geometry.sectors;
279                         g_cylinders = geometry.cylinders;
280                 } else {
281                         g_heads = 0;
282                         g_sectors = 0;
283                         g_cylinders = 0;
284                 }
285                 if (floppy) {
286                         sunlabel->nacyl = 0;
287                         sunlabel->pcylcount = SUN_SSWAP16(g_cylinders);
288                         sunlabel->rspeed = SUN_SSWAP16(300);
289                         sunlabel->ilfact = SUN_SSWAP16(1);
290                         sunlabel->sparecyl = 0;
291                 } else {
292                         g_heads = read_int(1, g_heads, 1024, 0, "Heads");
293                         g_sectors = read_int(1, g_sectors, 1024, 0, "Sectors/track");
294                 if (g_cylinders)
295                         g_cylinders = read_int(1, g_cylinders - 2, 65535, 0, "Cylinders");
296                 else
297                         g_cylinders = read_int(1, 0, 65535, 0, "Cylinders");
298                         sunlabel->nacyl = SUN_SSWAP16(read_int(0, 2, 65535, 0, "Alternate cylinders"));
299                         sunlabel->pcylcount = SUN_SSWAP16(read_int(0, g_cylinders + SUN_SSWAP16(sunlabel->nacyl), 65535, 0, "Physical cylinders"));
300                         sunlabel->rspeed = SUN_SSWAP16(read_int(1, 5400, 100000, 0, "Rotation speed (rpm)"));
301                         sunlabel->ilfact = SUN_SSWAP16(read_int(1, 1, 32, 0, "Interleave factor"));
302                         sunlabel->sparecyl = SUN_SSWAP16(read_int(0, 0, g_sectors, 0, "Extra sectors per cylinder"));
303                 }
304         } else {
305                 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
306                 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
307                 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
308                 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
309                 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
310                 sunlabel->nsect = SUN_SSWAP16(p->nsect);
311                 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
312                 sunlabel->ilfact = SUN_SSWAP16(1);
313                 g_cylinders = p->ncyl;
314                 g_heads = p->ntrks;
315                 g_sectors = p->nsect;
316                 puts("You may change all the disk params from the x menu");
317         }
318
319         snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
320                 "%s%s%s cyl %d alt %d hd %d sec %d",
321                 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
322                 p ? p->model : (floppy ? "3,5\" floppy" : "Linux custom"),
323                 g_cylinders, SUN_SSWAP16(sunlabel->nacyl), g_heads, g_sectors);
324
325         sunlabel->ntrks = SUN_SSWAP16(g_heads);
326         sunlabel->nsect = SUN_SSWAP16(g_sectors);
327         sunlabel->ncyl = SUN_SSWAP16(g_cylinders);
328         if (floppy)
329                 set_sun_partition(0, 0, g_cylinders * g_heads * g_sectors, LINUX_NATIVE);
330         else {
331                 if (g_cylinders * g_heads * g_sectors >= 150 * 2048) {
332                         ndiv = g_cylinders - (50 * 2048 / (g_heads * g_sectors)); /* 50M swap */
333                 } else
334                         ndiv = g_cylinders * 2 / 3;
335                 set_sun_partition(0, 0, ndiv * g_heads * g_sectors, LINUX_NATIVE);
336                 set_sun_partition(1, ndiv * g_heads * g_sectors, g_cylinders * g_heads * g_sectors, LINUX_SWAP);
337                 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
338         }
339         set_sun_partition(2, 0, g_cylinders * g_heads * g_sectors, SUN_WHOLE_DISK);
340         {
341                 unsigned short *ush = (unsigned short *)sunlabel;
342                 unsigned short csum = 0;
343                 while (ush < (unsigned short *)(&sunlabel->csum))
344                         csum ^= *ush++;
345                 sunlabel->csum = csum;
346         }
347
348         set_all_unchanged();
349         set_changed(0);
350         get_boot(CREATE_EMPTY_SUN);
351 }
352
353 static void
354 toggle_sunflags(int i, unsigned char mask)
355 {
356         if (sunlabel->infos[i].flags & mask)
357                 sunlabel->infos[i].flags &= ~mask;
358         else
359                 sunlabel->infos[i].flags |= mask;
360         set_changed(i);
361 }
362
363 static void
364 fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
365 {
366         int i, continuous = 1;
367
368         *start = 0;
369         *stop = g_cylinders * g_heads * g_sectors;
370         for (i = 0; i < g_partitions; i++) {
371                 if (sunlabel->partitions[i].num_sectors
372                  && sunlabel->infos[i].id
373                  && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
374                         starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
375                         lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
376                         if (continuous) {
377                                 if (starts[i] == *start)
378                                         *start += lens[i];
379                                 else if (starts[i] + lens[i] >= *stop)
380                                         *stop = starts[i];
381                                 else
382                                         continuous = 0;
383                                         /* There will be probably more gaps
384                                           than one, so lets check afterwards */
385                         }
386                 } else {
387                         starts[i] = 0;
388                         lens[i] = 0;
389                 }
390         }
391 }
392
393 static uint *verify_sun_starts;
394
395 static int
396 verify_sun_cmp(int *a, int *b)
397 {
398         if (*a == -1) return 1;
399         if (*b == -1) return -1;
400         if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
401         return -1;
402 }
403
404 static void
405 verify_sun(void)
406 {
407         uint starts[8], lens[8], start, stop;
408         int i,j,k,starto,endo;
409         int array[8];
410
411         verify_sun_starts = starts;
412         fetch_sun(starts, lens, &start, &stop);
413         for (k = 0; k < 7; k++) {
414                 for (i = 0; i < 8; i++) {
415                         if (k && (lens[i] % (g_heads * g_sectors))) {
416                                 printf("Partition %d doesn't end on cylinder boundary\n", i+1);
417                         }
418                         if (lens[i]) {
419                                 for (j = 0; j < i; j++)
420                                         if (lens[j]) {
421                                                 if (starts[j] == starts[i]+lens[i]) {
422                                                         starts[j] = starts[i]; lens[j] += lens[i];
423                                                         lens[i] = 0;
424                                                 } else if (starts[i] == starts[j]+lens[j]){
425                                                         lens[j] += lens[i];
426                                                         lens[i] = 0;
427                                                 } else if (!k) {
428                                                         if (starts[i] < starts[j]+lens[j]
429                                                          && starts[j] < starts[i]+lens[i]) {
430                                                                 starto = starts[i];
431                                                                 if (starts[j] > starto)
432                                                                         starto = starts[j];
433                                                                 endo = starts[i]+lens[i];
434                                                                 if (starts[j]+lens[j] < endo)
435                                                                         endo = starts[j]+lens[j];
436                                                                 printf("Partition %d overlaps with others in "
437                                                                         "sectors %d-%d\n", i+1, starto, endo);
438                                                         }
439                                                 }
440                                         }
441                         }
442                 }
443         }
444         for (i = 0; i < 8; i++) {
445                 if (lens[i])
446                         array[i] = i;
447                 else
448                         array[i] = -1;
449         }
450         qsort(array, ARRAY_SIZE(array), sizeof(array[0]),
451                 (int (*)(const void *,const void *)) verify_sun_cmp);
452         if (array[0] == -1) {
453                 printf("No partitions defined\n");
454                 return;
455         }
456         stop = g_cylinders * g_heads * g_sectors;
457         if (starts[array[0]])
458                 printf("Unused gap - sectors 0-%d\n", starts[array[0]]);
459         for (i = 0; i < 7 && array[i+1] != -1; i++) {
460                 printf("Unused gap - sectors %d-%d\n", starts[array[i]]+lens[array[i]], starts[array[i+1]]);
461         }
462         start = starts[array[i]] + lens[array[i]];
463         if (start < stop)
464                 printf("Unused gap - sectors %d-%d\n", start, stop);
465 }
466
467 static void
468 add_sun_partition(int n, int sys)
469 {
470         uint start, stop, stop2;
471         uint starts[8], lens[8];
472         int whole_disk = 0;
473
474         char mesg[256];
475         int i, first, last;
476
477         if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
478                 printf(msg_part_already_defined, n + 1);
479                 return;
480         }
481
482         fetch_sun(starts,lens,&start,&stop);
483         if (stop <= start) {
484                 if (n == 2)
485                         whole_disk = 1;
486                 else {
487                         printf("Other partitions already cover the whole disk.\n"
488                                 "Delete/shrink them before retry.\n");
489                         return;
490                 }
491         }
492         snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
493         while (1) {
494                 if (whole_disk)
495                         first = read_int(0, 0, 0, 0, mesg);
496                 else
497                         first = read_int(scround(start), scround(stop)+1,
498                                          scround(stop), 0, mesg);
499                 if (display_in_cyl_units)
500                         first *= units_per_sector;
501                 else
502                         /* Starting sector has to be properly aligned */
503                         first = (first + g_heads * g_sectors - 1) / (g_heads * g_sectors);
504                 if (n == 2 && first != 0)
505                         printf("\
506 It is highly recommended that the third partition covers the whole disk\n\
507 and is of type 'Whole disk'\n");
508                 /* ewt asks to add: "don't start a partition at cyl 0"
509                    However, edmundo@rano.demon.co.uk writes:
510                    "In addition to having a Sun partition table, to be able to
511                    boot from the disc, the first partition, /dev/sdX1, must
512                    start at cylinder 0. This means that /dev/sdX1 contains
513                    the partition table and the boot block, as these are the
514                    first two sectors of the disc. Therefore you must be
515                    careful what you use /dev/sdX1 for. In particular, you must
516                    not use a partition starting at cylinder 0 for Linux swap,
517                    as that would overwrite the partition table and the boot
518                    block. You may, however, use such a partition for a UFS
519                    or EXT2 file system, as these file systems leave the first
520                    1024 bytes undisturbed. */
521                 /* On the other hand, one should not use partitions
522                    starting at block 0 in an md, or the label will
523                    be trashed. */
524                 for (i = 0; i < g_partitions; i++)
525                         if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
526                                 break;
527                 if (i < g_partitions && !whole_disk) {
528                         if (n == 2 && !first) {
529                                 whole_disk = 1;
530                                 break;
531                         }
532                         printf("Sector %d is already allocated\n", first);
533                 } else
534                         break;
535         }
536         stop = g_cylinders * g_heads * g_sectors;
537         stop2 = stop;
538         for (i = 0; i < g_partitions; i++) {
539                 if (starts[i] > first && starts[i] < stop)
540                         stop = starts[i];
541         }
542         snprintf(mesg, sizeof(mesg),
543                 "Last %s or +size or +sizeM or +sizeK",
544                 str_units(SINGULAR));
545         if (whole_disk)
546                 last = read_int(scround(stop2), scround(stop2), scround(stop2),
547                                 0, mesg);
548         else if (n == 2 && !first)
549                 last = read_int(scround(first), scround(stop2), scround(stop2),
550                                 scround(first), mesg);
551         else
552                 last = read_int(scround(first), scround(stop), scround(stop),
553                                 scround(first), mesg);
554         if (display_in_cyl_units)
555                 last *= units_per_sector;
556         if (n == 2 && !first) {
557                 if (last >= stop2) {
558                         whole_disk = 1;
559                         last = stop2;
560                 } else if (last > stop) {
561                         printf(
562 "You haven't covered the whole disk with the 3rd partition,\n"
563 "but your value %d %s covers some other partition.\n"
564 "Your entry has been changed 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)) == g_heads * g_sectors * g_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, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed),
636                         g_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, g_heads, g_sectors, g_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 < g_partitions; i++) {
652                 if (sunlabel->partitions[i].num_sectors) {
653                         uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_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 #if ENABLE_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), g_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 /* 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         write_sector(0, sunlabel);
727 }
728 #endif /* SUN_LABEL */