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