busybox/util-linux/fdisk_sgi.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) Andreas Neuper, Sep 1998.
   3 *
   4 * Licensed under GPLv2, see file LICENSE in this tarball for details.
   5 */
   6
   7#if ENABLE_FEATURE_SGI_LABEL
   8
   9#define SGI_DEBUG 0
  10
  11#define SGI_VOLHDR      0x00
  12/* 1 and 2 were used for drive types no longer supported by SGI */
  13#define SGI_SWAP        0x03
  14/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
  15#define SGI_VOLUME      0x06
  16#define SGI_EFS         0x07
  17#define SGI_LVOL        0x08
  18#define SGI_RLVOL       0x09
  19#define SGI_XFS         0x0a
  20#define SGI_XFSLOG      0x0b
  21#define SGI_XLV         0x0c
  22#define SGI_XVM         0x0d
  23#define SGI_ENTIRE_DISK SGI_VOLUME
  24
  25struct device_parameter { /* 48 bytes */
  26        unsigned char  skew;
  27        unsigned char  gap1;
  28        unsigned char  gap2;
  29        unsigned char  sparecyl;
  30        unsigned short pcylcount;
  31        unsigned short head_vol0;
  32        unsigned short ntrks;   /* tracks in cyl 0 or vol 0 */
  33        unsigned char  cmd_tag_queue_depth;
  34        unsigned char  unused0;
  35        unsigned short unused1;
  36        unsigned short nsect;   /* sectors/tracks in cyl 0 or vol 0 */
  37        unsigned short bytes;
  38        unsigned short ilfact;
  39        unsigned int   flags;           /* controller flags */
  40        unsigned int   datarate;
  41        unsigned int   retries_on_error;
  42        unsigned int   ms_per_word;
  43        unsigned short xylogics_gap1;
  44        unsigned short xylogics_syncdelay;
  45        unsigned short xylogics_readdelay;
  46        unsigned short xylogics_gap2;
  47        unsigned short xylogics_readgate;
  48        unsigned short xylogics_writecont;
  49};
  50
  51/*
  52 * controller flags
  53 */
  54#define SECTOR_SLIP     0x01
  55#define SECTOR_FWD      0x02
  56#define TRACK_FWD       0x04
  57#define TRACK_MULTIVOL  0x08
  58#define IGNORE_ERRORS   0x10
  59#define RESEEK          0x20
  60#define ENABLE_CMDTAGQ  0x40
  61
  62typedef struct {
  63        unsigned int   magic;            /* expect SGI_LABEL_MAGIC */
  64        unsigned short boot_part;        /* active boot partition */
  65        unsigned short swap_part;        /* active swap partition */
  66        unsigned char  boot_file[16];    /* name of the bootfile */
  67        struct device_parameter devparam;       /*  1 * 48 bytes */
  68        struct volume_directory {               /* 15 * 16 bytes */
  69                unsigned char vol_file_name[8]; /* a character array */
  70                unsigned int  vol_file_start;   /* number of logical block */
  71                unsigned int  vol_file_size;    /* number of bytes */
  72        } directory[15];
  73        struct sgi_partinfo {                  /* 16 * 12 bytes */
  74                unsigned int num_sectors;       /* number of blocks */
  75                unsigned int start_sector;      /* must be cylinder aligned */
  76                unsigned int id;
  77        } partitions[16];
  78        unsigned int   csum;
  79        unsigned int   fillbytes;
  80} sgi_partition;
  81
  82typedef struct {
  83        unsigned int   magic;           /* looks like a magic number */
  84        unsigned int   a2;
  85        unsigned int   a3;
  86        unsigned int   a4;
  87        unsigned int   b1;
  88        unsigned short b2;
  89        unsigned short b3;
  90        unsigned int   c[16];
  91        unsigned short d[3];
  92        unsigned char  scsi_string[50];
  93        unsigned char  serial[137];
  94        unsigned short check1816;
  95        unsigned char  installer[225];
  96} sgiinfo;
  97
  98#define SGI_LABEL_MAGIC         0x0be5a941
  99#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
 100#define SGI_INFO_MAGIC          0x00072959
 101#define SGI_INFO_MAGIC_SWAPPED  0x59290700
 102
 103#define SGI_SSWAP16(x) (sgi_other_endian ? fdisk_swap16(x) : (uint16_t)(x))
 104#define SGI_SSWAP32(x) (sgi_other_endian ? fdisk_swap32(x) : (uint32_t)(x))
 105
 106#define sgilabel ((sgi_partition *)MBRbuffer)
 107#define sgiparam (sgilabel->devparam)
 108
 109/*
 110 *
 111 * fdisksgilabel.c
 112 *
 113 * Copyright (C) Andreas Neuper, Sep 1998.
 114 *      This file may be modified and redistributed under
 115 *      the terms of the GNU Public License.
 116 *
 117 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 118 *      Internationalization
 119 */
 120
 121
 122static smallint sgi_other_endian; /* bool */
 123static smallint sgi_volumes = 1; /* max 15 */
 124
 125/*
 126 * only dealing with free blocks here
 127 */
 128
 129typedef struct {
 130        unsigned int first;
 131        unsigned int last;
 132} freeblocks;
 133static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
 134
 135static void
 136setfreelist(int i, unsigned int f, unsigned int l)
 137{
 138        freelist[i].first = f;
 139        freelist[i].last = l;
 140}
 141
 142static void
 143add2freelist(unsigned int f, unsigned int l)
 144{
 145        int i;
 146        for (i = 0; i < 17; i++)
 147                if (freelist[i].last == 0)
 148                        break;
 149        setfreelist(i, f, l);
 150}
 151
 152static void
 153clearfreelist(void)
 154{
 155        int i;
 156
 157        for (i = 0; i < 17; i++)
 158                setfreelist(i, 0, 0);
 159}
 160
 161static unsigned int
 162isinfreelist(unsigned int b)
 163{
 164        int i;
 165
 166        for (i = 0; i < 17; i++)
 167                if (freelist[i].first <= b && freelist[i].last >= b)
 168                        return freelist[i].last;
 169        return 0;
 170}
 171        /* return last vacant block of this stride (never 0). */
 172        /* the '>=' is not quite correct, but simplifies the code */
 173/*
 174 * end of free blocks section
 175 */
 176
 177static const char *const sgi_sys_types[] = {
 178/* SGI_VOLHDR   */      "\x00" "SGI volhdr"  ,
 179/* 0x01         */      "\x01" "SGI trkrepl" ,
 180/* 0x02         */      "\x02" "SGI secrepl" ,
 181/* SGI_SWAP     */      "\x03" "SGI raw"     ,
 182/* 0x04         */      "\x04" "SGI bsd"     ,
 183/* 0x05         */      "\x05" "SGI sysv"    ,
 184/* SGI_ENTIRE_DISK  */  "\x06" "SGI volume"  ,
 185/* SGI_EFS      */      "\x07" "SGI efs"     ,
 186/* 0x08         */      "\x08" "SGI lvol"    ,
 187/* 0x09         */      "\x09" "SGI rlvol"   ,
 188/* SGI_XFS      */      "\x0a" "SGI xfs"     ,
 189/* SGI_XFSLOG   */      "\x0b" "SGI xfslog"  ,
 190/* SGI_XLV      */      "\x0c" "SGI xlv"     ,
 191/* SGI_XVM      */      "\x0d" "SGI xvm"     ,
 192/* LINUX_SWAP   */      "\x82" "Linux swap"  ,
 193/* LINUX_NATIVE */      "\x83" "Linux native",
 194/* LINUX_LVM    */      "\x8d" "Linux LVM"   ,
 195/* LINUX_RAID   */      "\xfd" "Linux RAID"  ,
 196                        NULL
 197};
 198
 199
 200static int
 201sgi_get_nsect(void)
 202{
 203        return SGI_SSWAP16(sgilabel->devparam.nsect);
 204}
 205
 206static int
 207sgi_get_ntrks(void)
 208{
 209        return SGI_SSWAP16(sgilabel->devparam.ntrks);
 210}
 211
 212static unsigned int
 213two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
 214{
 215        int i = 0;
 216        unsigned int sum = 0;
 217
 218        size /= sizeof(unsigned int);
 219        for (i = 0; i < size; i++)
 220                sum -= SGI_SSWAP32(base[i]);
 221        return sum;
 222}
 223
 224void BUG_bad_sgi_partition_size(void);
 225
 226static int
 227check_sgi_label(void)
 228{
 229        if (sizeof(sgi_partition) > 512) {
 230                /* According to MIPS Computer Systems, Inc the label
 231                 * must not contain more than 512 bytes */
 232                BUG_bad_sgi_partition_size();
 233        }
 234
 235        if (sgilabel->magic != SGI_LABEL_MAGIC
 236         && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED
 237        ) {
 238                current_label_type = LABEL_DOS;
 239                return 0;
 240        }
 241
 242        sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
 243        /*
 244         * test for correct checksum
 245         */
 246        if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
 247                                sizeof(*sgilabel))) {
 248                printf("Detected sgi disklabel with wrong checksum\n");
 249        }
 250        update_units();
 251        current_label_type = LABEL_SGI;
 252        g_partitions = 16;
 253        sgi_volumes = 15;
 254        return 1;
 255}
 256
 257static unsigned int
 258sgi_get_start_sector(int i)
 259{
 260        return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
 261}
 262
 263static unsigned int
 264sgi_get_num_sectors(int i)
 265{
 266        return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
 267}
 268
 269static int
 270sgi_get_sysid(int i)
 271{
 272        return SGI_SSWAP32(sgilabel->partitions[i].id);
 273}
 274
 275static int
 276sgi_get_bootpartition(void)
 277{
 278        return SGI_SSWAP16(sgilabel->boot_part);
 279}
 280
 281static int
 282sgi_get_swappartition(void)
 283{
 284        return SGI_SSWAP16(sgilabel->swap_part);
 285}
 286
 287static void
 288sgi_list_table(int xtra)
 289{
 290        int i, w, wd;
 291        int kpi = 0;                /* kernel partition ID */
 292
 293        if (xtra) {
 294                printf("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
 295                        "%d cylinders, %d physical cylinders\n"
 296                        "%d extra sects/cyl, interleave %d:1\n"
 297                        "%s\n"
 298                        "Units = %s of %d * 512 bytes\n\n",
 299                        disk_device, g_heads, g_sectors, g_cylinders,
 300                        SGI_SSWAP16(sgiparam.pcylcount),
 301                        SGI_SSWAP16(sgiparam.sparecyl),
 302                        SGI_SSWAP16(sgiparam.ilfact),
 303                        (char *)sgilabel,
 304                        str_units(PLURAL), units_per_sector);
 305        } else {
 306                printf("\nDisk %s (SGI disk label): "
 307                        "%d heads, %d sectors, %d cylinders\n"
 308                        "Units = %s of %d * 512 bytes\n\n",
 309                        disk_device, g_heads, g_sectors, g_cylinders,
 310                        str_units(PLURAL), units_per_sector );
 311        }
 312
 313        w = strlen(disk_device);
 314        wd = sizeof("Device") - 1;
 315        if (w < wd)
 316        w = wd;
 317
 318        printf("----- partitions -----\n"
 319                "Pt# %*s  Info     Start       End   Sectors  Id  System\n",
 320                w + 2, "Device");
 321        for (i = 0; i < g_partitions; i++) {
 322                if (sgi_get_num_sectors(i) || SGI_DEBUG) {
 323                        uint32_t start = sgi_get_start_sector(i);
 324                        uint32_t len = sgi_get_num_sectors(i);
 325                        kpi++;              /* only count nonempty partitions */
 326                        printf(
 327                        "%2d: %s %4s %9ld %9ld %9ld  %2x  %s\n",
 328/* fdisk part number */ i+1,
 329/* device */            partname(disk_device, kpi, w+3),
 330/* flags */             (sgi_get_swappartition() == i) ? "swap" :
 331/* flags */             (sgi_get_bootpartition() == i) ? "boot" : "    ",
 332/* start */             (long) scround(start),
 333/* end */               (long) scround(start+len)-1,
 334/* no odd flag on end */(long) len,
 335/* type id */           sgi_get_sysid(i),
 336/* type name */         partition_type(sgi_get_sysid(i)));
 337                }
 338        }
 339        printf("----- Bootinfo -----\nBootfile: %s\n"
 340                "----- Directory Entries -----\n",
 341                sgilabel->boot_file);
 342        for (i = 0; i < sgi_volumes; i++) {
 343                if (sgilabel->directory[i].vol_file_size) {
 344                        uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
 345                        uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
 346                        unsigned char *name = sgilabel->directory[i].vol_file_name;
 347
 348                        printf("%2d: %-10s sector%5u size%8u\n",
 349                                i, (char*)name, (unsigned int) start, (unsigned int) len);
 350                }
 351        }
 352}
 353
 354static void
 355sgi_set_bootpartition(int i)
 356{
 357        sgilabel->boot_part = SGI_SSWAP16(((short)i));
 358}
 359
 360static unsigned int
 361sgi_get_lastblock(void)
 362{
 363        return g_heads * g_sectors * g_cylinders;
 364}
 365
 366static void
 367sgi_set_swappartition(int i)
 368{
 369        sgilabel->swap_part = SGI_SSWAP16(((short)i));
 370}
 371
 372static int
 373sgi_check_bootfile(const char* aFile)
 374{
 375        if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
 376                printf("\nInvalid Bootfile!\n"
 377                        "\tThe bootfile must be an absolute non-zero pathname,\n"
 378                        "\te.g. \"/unix\" or \"/unix.save\".\n");
 379                return 0;
 380        }
 381        if (strlen(aFile) > 16) {
 382                printf("\nName of Bootfile too long (>16 bytes)\n");
 383                return 0;
 384        }
 385        if (aFile[0] != '/') {
 386                printf("\nBootfile must have a fully qualified pathname\n");
 387                return 0;
 388        }
 389        if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
 390                printf("\nBe aware, that the bootfile is not checked for existence.\n"
 391                         "\tSGI's default is \"/unix\" and for backup \"/unix.save\".\n");
 392                /* filename is correct and did change */
 393                return 1;
 394        }
 395        return 0;   /* filename did not change */
 396}
 397
 398static const char *
 399sgi_get_bootfile(void)
 400{
 401        return (char*)sgilabel->boot_file;
 402}
 403
 404static void
 405sgi_set_bootfile(const char* aFile)
 406{
 407        int i = 0;
 408
 409        if (sgi_check_bootfile(aFile)) {
 410                while (i < 16) {
 411                        if ((aFile[i] != '\n')  /* in principle caught again by next line */
 412                         && (strlen(aFile) > i))
 413                                sgilabel->boot_file[i] = aFile[i];
 414                        else
 415                                sgilabel->boot_file[i] = 0;
 416                        i++;
 417                }
 418                printf("\n\tBootfile is changed to \"%s\"\n", sgilabel->boot_file);
 419        }
 420}
 421
 422static void
 423create_sgiinfo(void)
 424{
 425        /* I keep SGI's habit to write the sgilabel to the second block */
 426        sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
 427        sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
 428        strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
 429}
 430
 431static sgiinfo *fill_sgiinfo(void);
 432
 433static void
 434sgi_write_table(void)
 435{
 436        sgilabel->csum = 0;
 437        sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
 438                        (unsigned int*)sgilabel, sizeof(*sgilabel)));
 439        assert(two_s_complement_32bit_sum(
 440                (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
 441
 442        write_sector(0, sgilabel);
 443        if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
 444                /*
 445                 * keep this habit of first writing the "sgilabel".
 446                 * I never tested whether it works without (AN 981002).
 447                 */
 448                sgiinfo *info = fill_sgiinfo();
 449                int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
 450                write_sector(infostartblock, info);
 451                free(info);
 452        }
 453}
 454
 455static int
 456compare_start(int *x, int *y)
 457{
 458        /*
 459         * sort according to start sectors
 460         * and prefers largest partition:
 461         * entry zero is entire disk entry
 462         */
 463        unsigned int i = *x;
 464        unsigned int j = *y;
 465        unsigned int a = sgi_get_start_sector(i);
 466        unsigned int b = sgi_get_start_sector(j);
 467        unsigned int c = sgi_get_num_sectors(i);
 468        unsigned int d = sgi_get_num_sectors(j);
 469
 470        if (a == b)
 471                return (d > c) ? 1 : (d == c) ? 0 : -1;
 472        return (a > b) ? 1 : -1;
 473}
 474
 475
 476static int
 477verify_sgi(int verbose)
 478{
 479        int Index[16];      /* list of valid partitions */
 480        int sortcount = 0;  /* number of used partitions, i.e. non-zero lengths */
 481        int entire = 0, i = 0;
 482        unsigned int start = 0;
 483        long long gap = 0;      /* count unused blocks */
 484        unsigned int lastblock = sgi_get_lastblock();
 485
 486        clearfreelist();
 487        for (i = 0; i < 16; i++) {
 488                if (sgi_get_num_sectors(i) != 0) {
 489                        Index[sortcount++] = i;
 490                        if (sgi_get_sysid(i) == SGI_ENTIRE_DISK) {
 491                                if (entire++ == 1) {
 492                                        if (verbose)
 493                                                printf("More than one entire disk entry present\n");
 494                                }
 495                        }
 496                }
 497        }
 498        if (sortcount == 0) {
 499                if (verbose)
 500                        printf("No partitions defined\n");
 501                return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
 502        }
 503        qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
 504        if (sgi_get_sysid(Index[0]) == SGI_ENTIRE_DISK) {
 505                if ((Index[0] != 10) && verbose)
 506                        printf("IRIX likes when Partition 11 covers the entire disk\n");
 507                if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
 508                        printf("The entire disk partition should start "
 509                                "at block 0,\n"
 510                                "not at diskblock %d\n",
 511                                sgi_get_start_sector(Index[0]));
 512                if (SGI_DEBUG)      /* I do not understand how some disks fulfil it */
 513                        if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
 514                                printf("The entire disk partition is only %d diskblock large,\n"
 515                                        "but the disk is %d diskblocks long\n",
 516                                        sgi_get_num_sectors(Index[0]), lastblock);
 517                        lastblock = sgi_get_num_sectors(Index[0]);
 518        } else {
 519                if (verbose)
 520                        printf("One Partition (#11) should cover the entire disk\n");
 521                if (SGI_DEBUG > 2)
 522                        printf("sysid=%d\tpartition=%d\n",
 523                                sgi_get_sysid(Index[0]), Index[0]+1);
 524        }
 525        for (i = 1, start = 0; i < sortcount; i++) {
 526                int cylsize = sgi_get_nsect() * sgi_get_ntrks();
 527
 528                if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
 529                        if (SGI_DEBUG)      /* I do not understand how some disks fulfil it */
 530                                if (verbose)
 531                                        printf("Partition %d does not start on cylinder boundary\n",
 532                                                Index[i]+1);
 533                }
 534                if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
 535                        if (SGI_DEBUG)      /* I do not understand how some disks fulfil it */
 536                                if (verbose)
 537                                        printf("Partition %d does not end on cylinder boundary\n",
 538                                                Index[i]+1);
 539                }
 540                /* We cannot handle several "entire disk" entries. */
 541                if (sgi_get_sysid(Index[i]) == SGI_ENTIRE_DISK) continue;
 542                if (start > sgi_get_start_sector(Index[i])) {
 543                        if (verbose)
 544                                printf("Partitions %d and %d overlap by %d sectors\n",
 545                                        Index[i-1]+1, Index[i]+1,
 546                                        start - sgi_get_start_sector(Index[i]));
 547                        if (gap > 0) gap = -gap;
 548                        if (gap == 0) gap = -1;
 549                }
 550                if (start < sgi_get_start_sector(Index[i])) {
 551                        if (verbose)
 552                                printf("Unused gap of %8u sectors - sectors %8u-%8u\n",
 553                                        sgi_get_start_sector(Index[i]) - start,
 554                                        start, sgi_get_start_sector(Index[i])-1);
 555                        gap += sgi_get_start_sector(Index[i]) - start;
 556                        add2freelist(start, sgi_get_start_sector(Index[i]));
 557                }
 558                start = sgi_get_start_sector(Index[i])
 559                           + sgi_get_num_sectors(Index[i]);
 560                if (SGI_DEBUG > 1) {
 561                        if (verbose)
 562                                printf("%2d:%12d\t%12d\t%12d\n", Index[i],
 563                                        sgi_get_start_sector(Index[i]),
 564                                        sgi_get_num_sectors(Index[i]),
 565                                        sgi_get_sysid(Index[i]));
 566                }
 567        }
 568        if (start < lastblock) {
 569                if (verbose)
 570                        printf("Unused gap of %8u sectors - sectors %8u-%8u\n",
 571                                lastblock - start, start, lastblock-1);
 572                gap += lastblock - start;
 573                add2freelist(start, lastblock);
 574        }
 575        /*
 576         * Done with arithmetics
 577         * Go for details now
 578         */
 579        if (verbose) {
 580                if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
 581                        printf("\nThe boot partition does not exist\n");
 582                }
 583                if (!sgi_get_num_sectors(sgi_get_swappartition())) {
 584                        printf("\nThe swap partition does not exist\n");
 585                } else {
 586                        if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
 587                         && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
 588                                printf("\nThe swap partition has no swap type\n");
 589                }
 590                if (sgi_check_bootfile("/unix"))
 591                        printf("\tYou have chosen an unusual boot file name\n");
 592        }
 593        return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
 594}
 595
 596static int
 597sgi_gaps(void)
 598{
 599        /*
 600         * returned value is:
 601         *  = 0 : disk is properly filled to the rim
 602         *  < 0 : there is an overlap
 603         *  > 0 : there is still some vacant space
 604         */
 605        return verify_sgi(0);
 606}
 607
 608static void
 609sgi_change_sysid(int i, int sys)
 610{
 611        if (sgi_get_num_sectors(i) == 0) { /* caught already before, ... */
 612                printf("Sorry you may change the Tag of non-empty partitions\n");
 613                return;
 614        }
 615        if ((sys != SGI_ENTIRE_DISK) && (sys != SGI_VOLHDR)
 616         && (sgi_get_start_sector(i) < 1)
 617        ) {
 618                read_maybe_empty(
 619                        "It is highly recommended that the partition at offset 0\n"
 620                        "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
 621                        "retrieve from its directory standalone tools like sash and fx.\n"
 622                        "Only the \"SGI volume\" entire disk section may violate this.\n"
 623                        "Type YES if you are sure about tagging this partition differently.\n");
 624                if (strcmp(line_ptr, "YES\n") != 0)
 625                        return;
 626        }
 627        sgilabel->partitions[i].id = SGI_SSWAP32(sys);
 628}
 629
 630/* returns partition index of first entry marked as entire disk */
 631static int
 632sgi_entire(void)
 633{
 634        int i;
 635
 636        for (i = 0; i < 16; i++)
 637                if (sgi_get_sysid(i) == SGI_VOLUME)
 638                        return i;
 639        return -1;
 640}
 641
 642static void
 643sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
 644{
 645        sgilabel->partitions[i].id = SGI_SSWAP32(sys);
 646        sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
 647        sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
 648        set_changed(i);
 649        if (sgi_gaps() < 0)     /* rebuild freelist */
 650                printf("Partition overlap detected\n");
 651}
 652
 653static void
 654sgi_set_entire(void)
 655{
 656        int n;
 657
 658        for (n = 10; n < g_partitions; n++) {
 659                if (!sgi_get_num_sectors(n) ) {
 660                        sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
 661                        break;
 662                }
 663        }
 664}
 665
 666static void
 667sgi_set_volhdr(void)
 668{
 669        int n;
 670
 671        for (n = 8; n < g_partitions; n++) {
 672        if (!sgi_get_num_sectors(n)) {
 673                /*
 674                 * 5 cylinders is an arbitrary value I like
 675                 * IRIX 5.3 stored files in the volume header
 676                 * (like sash, symmon, fx, ide) with ca. 3200
 677                 * sectors.
 678                 */
 679                if (g_heads * g_sectors * 5 < sgi_get_lastblock())
 680                        sgi_set_partition(n, 0, g_heads * g_sectors * 5, SGI_VOLHDR);
 681                        break;
 682                }
 683        }
 684}
 685
 686static void
 687sgi_delete_partition(int i)
 688{
 689        sgi_set_partition(i, 0, 0, 0);
 690}
 691
 692static void
 693sgi_add_partition(int n, int sys)
 694{
 695        char mesg[256];
 696        unsigned int first = 0, last = 0;
 697
 698        if (n == 10) {
 699                sys = SGI_VOLUME;
 700        } else if (n == 8) {
 701                sys = 0;
 702        }
 703        if (sgi_get_num_sectors(n)) {
 704                printf(msg_part_already_defined, n + 1);
 705                return;
 706        }
 707        if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
 708                printf("Attempting to generate entire disk entry automatically\n");
 709                sgi_set_entire();
 710                sgi_set_volhdr();
 711        }
 712        if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
 713                printf("The entire disk is already covered with partitions\n");
 714                return;
 715        }
 716        if (sgi_gaps() < 0) {
 717                printf("You got a partition overlap on the disk. Fix it first!\n");
 718                return;
 719        }
 720        snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
 721        while (1) {
 722                if (sys == SGI_VOLUME) {
 723                        last = sgi_get_lastblock();
 724                        first = read_int(0, 0, last-1, 0, mesg);
 725                        if (first != 0) {
 726                                printf("It is highly recommended that eleventh partition\n"
 727                                                "covers the entire disk and is of type 'SGI volume'\n");
 728                        }
 729                } else {
 730                        first = freelist[0].first;
 731                        last  = freelist[0].last;
 732                        first = read_int(scround(first), scround(first), scround(last)-1,
 733                                0, mesg);
 734                }
 735                if (display_in_cyl_units)
 736                        first *= units_per_sector;
 737                else
 738                        first = first; /* align to cylinder if you know how ... */
 739                if (!last )
 740                        last = isinfreelist(first);
 741                if (last != 0)
 742                        break;
 743                printf("You will get a partition overlap on the disk. "
 744                                "Fix it first!\n");
 745        }
 746        snprintf(mesg, sizeof(mesg), " Last %s", str_units(SINGULAR));
 747        last = read_int(scround(first), scround(last)-1, scround(last)-1,
 748                        scround(first), mesg)+1;
 749        if (display_in_cyl_units)
 750                last *= units_per_sector;
 751        else
 752                last = last; /* align to cylinder if You know how ... */
 753        if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
 754                printf("It is highly recommended that eleventh partition\n"
 755                        "covers the entire disk and is of type 'SGI volume'\n");
 756        sgi_set_partition(n, first, last-first, sys);
 757}
 758
 759#if ENABLE_FEATURE_FDISK_ADVANCED
 760static void
 761create_sgilabel(void)
 762{
 763        struct hd_geometry geometry;
 764        struct {
 765                unsigned int start;
 766                unsigned int nsect;
 767                int sysid;
 768        } old[4];
 769        int i = 0;
 770        long longsectors;               /* the number of sectors on the device */
 771        int res;                        /* the result from the ioctl */
 772        int sec_fac;                    /* the sector factor */
 773
 774        sec_fac = sector_size / 512;    /* determine the sector factor */
 775
 776        printf(msg_building_new_label, "SGI disklabel");
 777
 778        sgi_other_endian = BB_LITTLE_ENDIAN;
 779        res = ioctl(dev_fd, BLKGETSIZE, &longsectors);
 780        if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
 781                g_heads = geometry.heads;
 782                g_sectors = geometry.sectors;
 783                if (res == 0) {
 784                        /* the get device size ioctl was successful */
 785                        g_cylinders = longsectors / (g_heads * g_sectors);
 786                        g_cylinders /= sec_fac;
 787                } else {
 788                        /* otherwise print error and use truncated version */
 789                        g_cylinders = geometry.cylinders;
 790                        printf(
 791"Warning: BLKGETSIZE ioctl failed on %s.  Using geometry cylinder value of %d.\n"
 792"This value may be truncated for devices > 33.8 GB.\n", disk_device, g_cylinders);
 793                }
 794        }
 795        for (i = 0; i < 4; i++) {
 796                old[i].sysid = 0;
 797                if (valid_part_table_flag(MBRbuffer)) {
 798                        if (get_part_table(i)->sys_ind) {
 799                                old[i].sysid = get_part_table(i)->sys_ind;
 800                                old[i].start = get_start_sect(get_part_table(i));
 801                                old[i].nsect = get_nr_sects(get_part_table(i));
 802                                printf("Trying to keep parameters of partition %d\n", i);
 803                                if (SGI_DEBUG)
 804                                        printf("ID=%02x\tSTART=%d\tLENGTH=%d\n",
 805                                old[i].sysid, old[i].start, old[i].nsect);
 806                        }
 807                }
 808        }
 809
 810        memset(MBRbuffer, 0, sizeof(MBRbuffer));
 811        /* fields with '//' are already zeroed out by memset above */
 812
 813        sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
 814        //sgilabel->boot_part = SGI_SSWAP16(0);
 815        sgilabel->swap_part = SGI_SSWAP16(1);
 816
 817        //memset(sgilabel->boot_file, 0, 16);
 818        strcpy((char*)sgilabel->boot_file, "/unix"); /* sizeof(sgilabel->boot_file) == 16 > 6 */
 819
 820        //sgilabel->devparam.skew                     = (0);
 821        //sgilabel->devparam.gap1                     = (0);
 822        //sgilabel->devparam.gap2                     = (0);
 823        //sgilabel->devparam.sparecyl                 = (0);
 824        sgilabel->devparam.pcylcount                = SGI_SSWAP16(geometry.cylinders);
 825        //sgilabel->devparam.head_vol0                = SGI_SSWAP16(0);
 826        /* tracks/cylinder (heads) */
 827        sgilabel->devparam.ntrks                    = SGI_SSWAP16(geometry.heads);
 828        //sgilabel->devparam.cmd_tag_queue_depth      = (0);
 829        //sgilabel->devparam.unused0                  = (0);
 830        //sgilabel->devparam.unused1                  = SGI_SSWAP16(0);
 831        /* sectors/track */
 832        sgilabel->devparam.nsect                    = SGI_SSWAP16(geometry.sectors);
 833        sgilabel->devparam.bytes                    = SGI_SSWAP16(512);
 834        sgilabel->devparam.ilfact                   = SGI_SSWAP16(1);
 835        sgilabel->devparam.flags                    = SGI_SSWAP32(TRACK_FWD|
 836                                                        IGNORE_ERRORS|RESEEK);
 837        //sgilabel->devparam.datarate                 = SGI_SSWAP32(0);
 838        sgilabel->devparam.retries_on_error         = SGI_SSWAP32(1);
 839        //sgilabel->devparam.ms_per_word              = SGI_SSWAP32(0);
 840        //sgilabel->devparam.xylogics_gap1            = SGI_SSWAP16(0);
 841        //sgilabel->devparam.xylogics_syncdelay       = SGI_SSWAP16(0);
 842        //sgilabel->devparam.xylogics_readdelay       = SGI_SSWAP16(0);
 843        //sgilabel->devparam.xylogics_gap2            = SGI_SSWAP16(0);
 844        //sgilabel->devparam.xylogics_readgate        = SGI_SSWAP16(0);
 845        //sgilabel->devparam.xylogics_writecont       = SGI_SSWAP16(0);
 846        //memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
 847        //memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partinfo)*16 );
 848        current_label_type = LABEL_SGI;
 849        g_partitions = 16;
 850        sgi_volumes = 15;
 851        sgi_set_entire();
 852        sgi_set_volhdr();
 853        for (i = 0; i < 4; i++) {
 854                if (old[i].sysid) {
 855                        sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
 856                }
 857        }
 858}
 859
 860static void
 861sgi_set_xcyl(void)
 862{
 863        /* do nothing in the beginning */
 864}
 865#endif /* FEATURE_FDISK_ADVANCED */
 866
 867/* _____________________________________________________________
 868 */
 869
 870static sgiinfo *
 871fill_sgiinfo(void)
 872{
 873        sgiinfo *info = xzalloc(sizeof(sgiinfo));
 874
 875        info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
 876        info->b1 = SGI_SSWAP32(-1);
 877        info->b2 = SGI_SSWAP16(-1);
 878        info->b3 = SGI_SSWAP16(1);
 879        /* You may want to replace this string !!!!!!! */
 880        strcpy( (char*)info->scsi_string, "IBM OEM 0662S12         3 30" );
 881        strcpy( (char*)info->serial, "0000" );
 882        info->check1816 = SGI_SSWAP16(18*256 +16 );
 883        strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
 884        return info;
 885}
 886#endif /* SGI_LABEL */
 887