busybox/util-linux/fdisk_sun.c
<<
>>
Prefs
   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
  30static int sun_other_endian;
  31static int scsi_disk;
  32static 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
  41static void
  42guess_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
  64static 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
  83static void
  84set_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
  94static int
  95check_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
 125static 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
 157static const struct sun_predefined_drives *
 158sun_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
 230static void
 231create_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
 353static void
 354toggle_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
 363static void
 364fetch_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
 393static uint *verify_sun_starts;
 394
 395static int
 396verify_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
 404static void
 405verify_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
 467static void
 468add_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("\
 506It is highly recommended that the third partition covers the whole disk\n\
 507and 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
 577static void
 578sun_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
 594static void
 595sun_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
 622static void
 623sun_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
 670static void
 671sun_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
 678static void
 679sun_set_ncyl(int cyl)
 680{
 681        sunlabel->ncyl = SUN_SSWAP16(cyl);
 682}
 683
 684static void
 685sun_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
 692static void
 693sun_set_ilfact(void)
 694{
 695        sunlabel->ilfact =
 696                SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
 697                                "Interleave factor"));
 698}
 699
 700static void
 701sun_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
 708static void
 709sun_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
 717static void
 718sun_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 */
 729