bigbiff | 7b4c7a6 | 2015-01-01 19:44:14 -0500 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org> |
| 4 | * 2013 Karel Zak <kzak@redhat.com> |
| 5 | * |
| 6 | * This is a re-written version for libfdisk, the original was fdisksgilabel.c |
| 7 | * from util-linux fdisk, by: |
| 8 | * |
| 9 | * Andreas Neuper, Sep 1998, |
| 10 | * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, Mar 1999, |
| 11 | * Phillip Kesling <pkesling@sgi.com>, Mar 2003. |
| 12 | */ |
| 13 | |
| 14 | #include "c.h" |
| 15 | #include "nls.h" |
| 16 | #include "all-io.h" |
| 17 | |
| 18 | #include "blkdev.h" |
| 19 | |
| 20 | #include "bitops.h" |
| 21 | #include "pt-sgi.h" |
| 22 | #include "pt-mbr.h" |
| 23 | #include "fdiskP.h" |
| 24 | |
| 25 | /** |
| 26 | * SECTION: sgi |
| 27 | * @title: SGI |
| 28 | * @short_description: disk label specific functions |
| 29 | * |
| 30 | */ |
| 31 | |
| 32 | /* |
| 33 | * in-memory fdisk SGI stuff |
| 34 | */ |
| 35 | struct fdisk_sgi_label { |
| 36 | struct fdisk_label head; /* generic fdisk part */ |
| 37 | struct sgi_disklabel *header; /* on-disk data (pointer to cxt->firstsector) */ |
| 38 | |
| 39 | struct sgi_freeblocks { |
| 40 | unsigned int first; |
| 41 | unsigned int last; |
| 42 | } freelist[SGI_MAXPARTITIONS + 1]; |
| 43 | }; |
| 44 | |
| 45 | static struct fdisk_parttype sgi_parttypes[] = |
| 46 | { |
| 47 | {SGI_TYPE_VOLHDR, N_("SGI volhdr")}, |
| 48 | {SGI_TYPE_TRKREPL, N_("SGI trkrepl")}, |
| 49 | {SGI_TYPE_SECREPL, N_("SGI secrepl")}, |
| 50 | {SGI_TYPE_SWAP, N_("SGI raw")}, |
| 51 | {SGI_TYPE_BSD, N_("SGI bsd")}, |
| 52 | {SGI_TYPE_SYSV, N_("SGI sysv")}, |
| 53 | {SGI_TYPE_ENTIRE_DISK, N_("SGI volume")}, |
| 54 | {SGI_TYPE_EFS, N_("SGI efs")}, |
| 55 | {SGI_TYPE_LVOL, N_("SGI lvol")}, |
| 56 | {SGI_TYPE_RLVOL, N_("SGI rlvol")}, |
| 57 | {SGI_TYPE_XFS, N_("SGI xfs")}, |
| 58 | {SGI_TYPE_XFSLOG, N_("SGI xfslog")}, |
| 59 | {SGI_TYPE_XLV, N_("SGI xlv")}, |
| 60 | {SGI_TYPE_XVM, N_("SGI xvm")}, |
| 61 | {MBR_LINUX_SWAP_PARTITION, N_("Linux swap")}, |
| 62 | {MBR_LINUX_DATA_PARTITION, N_("Linux native")}, |
| 63 | {MBR_LINUX_LVM_PARTITION, N_("Linux LVM")}, |
| 64 | {MBR_LINUX_RAID_PARTITION, N_("Linux RAID")}, |
| 65 | {0, NULL } |
| 66 | }; |
| 67 | |
| 68 | static unsigned int sgi_get_start_sector(struct fdisk_context *cxt, int i ); |
| 69 | static unsigned int sgi_get_num_sectors(struct fdisk_context *cxt, int i ); |
| 70 | static int sgi_get_bootpartition(struct fdisk_context *cxt); |
| 71 | static int sgi_get_swappartition(struct fdisk_context *cxt); |
| 72 | |
| 73 | /* Returns a pointer buffer with on-disk data. */ |
| 74 | static inline struct sgi_disklabel *self_disklabel(struct fdisk_context *cxt) |
| 75 | { |
| 76 | assert(cxt); |
| 77 | assert(cxt->label); |
| 78 | assert(fdisk_is_label(cxt, SGI)); |
| 79 | |
| 80 | return ((struct fdisk_sgi_label *) cxt->label)->header; |
| 81 | } |
| 82 | |
| 83 | /* Returns in-memory fdisk data. */ |
| 84 | static inline struct fdisk_sgi_label *self_label(struct fdisk_context *cxt) |
| 85 | { |
| 86 | assert(cxt); |
| 87 | assert(cxt->label); |
| 88 | assert(fdisk_is_label(cxt, SGI)); |
| 89 | |
| 90 | return (struct fdisk_sgi_label *) cxt->label; |
| 91 | } |
| 92 | |
| 93 | /* |
| 94 | * Information within second on-disk block |
| 95 | */ |
| 96 | #define SGI_INFO_MAGIC 0x00072959 |
| 97 | |
| 98 | struct sgi_info { |
| 99 | unsigned int magic; /* looks like a magic number */ |
| 100 | unsigned int a2; |
| 101 | unsigned int a3; |
| 102 | unsigned int a4; |
| 103 | unsigned int b1; |
| 104 | unsigned short b2; |
| 105 | unsigned short b3; |
| 106 | unsigned int c[16]; |
| 107 | unsigned short d[3]; |
| 108 | unsigned char scsi_string[50]; |
| 109 | unsigned char serial[137]; |
| 110 | unsigned short check1816; |
| 111 | unsigned char installer[225]; |
| 112 | }; |
| 113 | |
| 114 | static struct sgi_info *sgi_new_info(void) |
| 115 | { |
| 116 | struct sgi_info *info = calloc(1, sizeof(struct sgi_info)); |
| 117 | |
| 118 | if (!info) |
| 119 | return NULL; |
| 120 | |
| 121 | info->magic = cpu_to_be32(SGI_INFO_MAGIC); |
| 122 | info->b1 = cpu_to_be32(-1); |
| 123 | info->b2 = cpu_to_be16(-1); |
| 124 | info->b3 = cpu_to_be16(1); |
| 125 | |
| 126 | /* You may want to replace this string !!!!!!! */ |
| 127 | strcpy((char *) info->scsi_string, "IBM OEM 0662S12 3 30"); |
| 128 | strcpy((char *) info->serial, "0000"); |
| 129 | info->check1816 = cpu_to_be16(18 * 256 + 16); |
| 130 | strcpy((char *) info->installer, "Sfx version 5.3, Oct 18, 1994"); |
| 131 | |
| 132 | return info; |
| 133 | } |
| 134 | |
| 135 | static void sgi_free_info(struct sgi_info *info) |
| 136 | { |
| 137 | free(info); |
| 138 | } |
| 139 | |
| 140 | /** |
| 141 | * fdisk_sgi_create_info: |
| 142 | * @cxt: context |
| 143 | * |
| 144 | * This function add hint about SGI label (e.g. set "sgilabel" as volume name) |
| 145 | * to the first SGI volume. This is probably old SGI convention without any |
| 146 | * effect to the device partitioning. |
| 147 | * |
| 148 | * Returns: 0 on success, <0 on error |
| 149 | */ |
| 150 | int fdisk_sgi_create_info(struct fdisk_context *cxt) |
| 151 | { |
| 152 | struct sgi_disklabel *sgilabel = self_disklabel(cxt); |
| 153 | |
| 154 | /* I keep SGI's habit to write the sgilabel to the second block */ |
| 155 | sgilabel->volume[0].block_num = cpu_to_be32(2); |
| 156 | sgilabel->volume[0].num_bytes = cpu_to_be32(sizeof(struct sgi_info)); |
| 157 | strncpy((char *) sgilabel->volume[0].name, "sgilabel", 8); |
| 158 | |
| 159 | fdisk_info(cxt, _("SGI info created on second sector.")); |
| 160 | return 0; |
| 161 | } |
| 162 | |
| 163 | |
| 164 | /* |
| 165 | * only dealing with free blocks here |
| 166 | */ |
| 167 | static void set_freelist(struct fdisk_context *cxt, |
| 168 | size_t i, unsigned int f, unsigned int l) |
| 169 | { |
| 170 | struct fdisk_sgi_label *sgi = self_label(cxt); |
| 171 | |
| 172 | if (i < ARRAY_SIZE(sgi->freelist)) { |
| 173 | sgi->freelist[i].first = f; |
| 174 | sgi->freelist[i].last = l; |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | static void add_to_freelist(struct fdisk_context *cxt, |
| 179 | unsigned int f, unsigned int l) |
| 180 | { |
| 181 | struct fdisk_sgi_label *sgi = self_label(cxt); |
| 182 | size_t i; |
| 183 | |
| 184 | for (i = 0; i < ARRAY_SIZE(sgi->freelist); i++) { |
| 185 | if (sgi->freelist[i].last == 0) |
| 186 | break; |
| 187 | } |
| 188 | set_freelist(cxt, i, f, l); |
| 189 | } |
| 190 | |
| 191 | static void clear_freelist(struct fdisk_context *cxt) |
| 192 | { |
| 193 | struct fdisk_sgi_label *sgi = self_label(cxt); |
| 194 | |
| 195 | memset(sgi->freelist, 0, sizeof(sgi->freelist)); |
| 196 | } |
| 197 | |
| 198 | static unsigned int is_in_freelist(struct fdisk_context *cxt, unsigned int b) |
| 199 | { |
| 200 | struct fdisk_sgi_label *sgi = self_label(cxt); |
| 201 | size_t i; |
| 202 | |
| 203 | for (i = 0; i < ARRAY_SIZE(sgi->freelist); i++) { |
| 204 | if (sgi->freelist[i].first <= b |
| 205 | && sgi->freelist[i].last >= b) |
| 206 | return sgi->freelist[i].last; |
| 207 | } |
| 208 | |
| 209 | return 0; |
| 210 | } |
| 211 | |
| 212 | |
| 213 | static int sgi_get_nsect(struct fdisk_context *cxt) |
| 214 | { |
| 215 | struct sgi_disklabel *sgilabel = self_disklabel(cxt); |
| 216 | return be16_to_cpu(sgilabel->devparam.nsect); |
| 217 | } |
| 218 | |
| 219 | static int sgi_get_ntrks(struct fdisk_context *cxt) |
| 220 | { |
| 221 | struct sgi_disklabel *sgilabel = self_disklabel(cxt); |
| 222 | return be16_to_cpu(sgilabel->devparam.ntrks); |
| 223 | } |
| 224 | |
| 225 | static size_t count_used_partitions(struct fdisk_context *cxt) |
| 226 | { |
| 227 | size_t i, ct = 0; |
| 228 | |
| 229 | for (i = 0; i < cxt->label->nparts_max; i++) |
| 230 | ct += sgi_get_num_sectors(cxt, i) > 0; |
| 231 | |
| 232 | return ct; |
| 233 | } |
| 234 | |
| 235 | static int sgi_probe_label(struct fdisk_context *cxt) |
| 236 | { |
| 237 | struct fdisk_sgi_label *sgi; |
| 238 | struct sgi_disklabel *sgilabel; |
| 239 | |
| 240 | assert(cxt); |
| 241 | assert(cxt->label); |
| 242 | assert(fdisk_is_label(cxt, SGI)); |
| 243 | assert(sizeof(struct sgi_disklabel) <= 512); |
| 244 | |
| 245 | /* map first sector to header */ |
| 246 | sgi = (struct fdisk_sgi_label *) cxt->label; |
| 247 | sgi->header = (struct sgi_disklabel *) cxt->firstsector; |
| 248 | sgilabel = sgi->header; |
| 249 | |
| 250 | if (be32_to_cpu(sgilabel->magic) != SGI_LABEL_MAGIC) { |
| 251 | sgi->header = NULL; |
| 252 | return 0; |
| 253 | } |
| 254 | |
| 255 | /* |
| 256 | * test for correct checksum |
| 257 | */ |
| 258 | if (sgi_pt_checksum(sgilabel) != 0) |
| 259 | fdisk_warnx(cxt, _("Detected an SGI disklabel with wrong checksum.")); |
| 260 | |
| 261 | clear_freelist(cxt); |
| 262 | cxt->label->nparts_max = SGI_MAXPARTITIONS; |
| 263 | cxt->label->nparts_cur = count_used_partitions(cxt); |
| 264 | return 1; |
| 265 | } |
| 266 | |
| 267 | static int sgi_list_table(struct fdisk_context *cxt) |
| 268 | { |
| 269 | struct sgi_disklabel *sgilabel = self_disklabel(cxt); |
| 270 | struct sgi_device_parameter *sgiparam = &sgilabel->devparam; |
| 271 | int rc = 0; |
| 272 | |
| 273 | if (fdisk_is_details(cxt)) |
| 274 | fdisk_info(cxt, _( |
| 275 | "Label geometry: %d heads, %llu sectors\n" |
| 276 | " %llu cylinders, %d physical cylinders\n" |
| 277 | " %d extra sects/cyl, interleave %d:1\n"), |
| 278 | cxt->geom.heads, cxt->geom.sectors, |
| 279 | cxt->geom.cylinders, be16_to_cpu(sgiparam->pcylcount), |
| 280 | (int) sgiparam->sparecyl, be16_to_cpu(sgiparam->ilfact)); |
| 281 | |
| 282 | fdisk_info(cxt, _("Bootfile: %s"), sgilabel->boot_file); |
| 283 | return rc; |
| 284 | } |
| 285 | |
| 286 | static unsigned int sgi_get_start_sector(struct fdisk_context *cxt, int i) |
| 287 | { |
| 288 | struct sgi_disklabel *sgilabel = self_disklabel(cxt); |
| 289 | return be32_to_cpu(sgilabel->partitions[i].first_block); |
| 290 | } |
| 291 | |
| 292 | static unsigned int sgi_get_num_sectors(struct fdisk_context *cxt, int i) |
| 293 | { |
| 294 | struct sgi_disklabel *sgilabel = self_disklabel(cxt); |
| 295 | return be32_to_cpu(sgilabel->partitions[i].num_blocks); |
| 296 | } |
| 297 | |
| 298 | static int sgi_get_sysid(struct fdisk_context *cxt, int i) |
| 299 | { |
| 300 | struct sgi_disklabel *sgilabel = self_disklabel(cxt); |
| 301 | return be32_to_cpu(sgilabel->partitions[i].type); |
| 302 | } |
| 303 | |
| 304 | static int sgi_get_bootpartition(struct fdisk_context *cxt) |
| 305 | { |
| 306 | struct sgi_disklabel *sgilabel = self_disklabel(cxt); |
| 307 | return be16_to_cpu(sgilabel->root_part_num); |
| 308 | } |
| 309 | |
| 310 | static int sgi_get_swappartition(struct fdisk_context *cxt) |
| 311 | { |
| 312 | struct sgi_disklabel *sgilabel = self_disklabel(cxt); |
| 313 | return be16_to_cpu(sgilabel->swap_part_num); |
| 314 | } |
| 315 | |
| 316 | static unsigned int sgi_get_lastblock(struct fdisk_context *cxt) |
| 317 | { |
| 318 | return cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders; |
| 319 | } |
| 320 | |
| 321 | static struct fdisk_parttype *sgi_get_parttype(struct fdisk_context *cxt, size_t n) |
| 322 | { |
| 323 | struct fdisk_parttype *t; |
| 324 | |
| 325 | if (n >= cxt->label->nparts_max) |
| 326 | return NULL; |
| 327 | |
| 328 | t = fdisk_label_get_parttype_from_code(cxt->label, sgi_get_sysid(cxt, n)); |
| 329 | return t ? : fdisk_new_unknown_parttype(sgi_get_sysid(cxt, n), NULL); |
| 330 | } |
| 331 | |
| 332 | /* fdisk_get_partition() backend */ |
| 333 | static int sgi_get_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partition *pa) |
| 334 | { |
| 335 | fdisk_sector_t start, len; |
| 336 | |
| 337 | pa->used = sgi_get_num_sectors(cxt, n) > 0; |
| 338 | if (!pa->used) |
| 339 | return 0; |
| 340 | |
| 341 | start = sgi_get_start_sector(cxt, n); |
| 342 | len = sgi_get_num_sectors(cxt, n); |
| 343 | |
| 344 | pa->type = sgi_get_parttype(cxt, n); |
| 345 | pa->size = len; |
| 346 | pa->start = start; |
| 347 | |
| 348 | if (pa->type && pa->type->code == SGI_TYPE_ENTIRE_DISK) |
| 349 | pa->wholedisk = 1; |
| 350 | |
| 351 | pa->attrs = sgi_get_swappartition(cxt) == (int) n ? "swap" : |
| 352 | sgi_get_bootpartition(cxt) == (int) n ? "boot" : NULL; |
| 353 | if (pa->attrs) |
| 354 | pa->attrs = strdup(pa->attrs); |
| 355 | |
| 356 | return 0; |
| 357 | } |
| 358 | |
| 359 | |
| 360 | static int sgi_check_bootfile(struct fdisk_context *cxt, const char *name) |
| 361 | { |
| 362 | size_t sz; |
| 363 | struct sgi_disklabel *sgilabel = self_disklabel(cxt); |
| 364 | |
| 365 | sz = strlen(name); |
| 366 | |
| 367 | if (sz < 3) { |
| 368 | /* "/a\n" is minimum */ |
| 369 | fdisk_warnx(cxt, _("Invalid bootfile! The bootfile must " |
| 370 | "be an absolute non-zero pathname, " |
| 371 | "e.g. \"/unix\" or \"/unix.save\".")); |
| 372 | return -EINVAL; |
| 373 | |
| 374 | } else if (sz > sizeof(sgilabel->boot_file)) { |
| 375 | fdisk_warnx(cxt, P_("Name of bootfile is too long: %zu byte maximum.", |
| 376 | "Name of bootfile is too long: %zu bytes maximum.", |
| 377 | sizeof(sgilabel->boot_file)), |
| 378 | sizeof(sgilabel->boot_file)); |
| 379 | return -EINVAL; |
| 380 | |
| 381 | } else if (*name != '/') { |
| 382 | fdisk_warnx(cxt, _("Bootfile must have a fully qualified pathname.")); |
| 383 | return -EINVAL; |
| 384 | } |
| 385 | |
| 386 | if (strncmp(name, (char *) sgilabel->boot_file, |
| 387 | sizeof(sgilabel->boot_file))) { |
| 388 | fdisk_warnx(cxt, _("Be aware that the bootfile is not checked " |
| 389 | "for existence. SGI's default is \"/unix\", " |
| 390 | "and for backup \"/unix.save\".")); |
| 391 | return 0; /* filename is correct and did change */ |
| 392 | } |
| 393 | |
| 394 | return 1; /* filename did not change */ |
| 395 | } |
| 396 | |
| 397 | /** |
| 398 | * fdisk_sgi_set_bootfile: |
| 399 | * @cxt: context |
| 400 | * |
| 401 | * Allows to set SGI boot file. The function uses Ask API for dialog with |
| 402 | * user. |
| 403 | * |
| 404 | * Returns: 0 on success, <0 on error |
| 405 | */ |
| 406 | int fdisk_sgi_set_bootfile(struct fdisk_context *cxt) |
| 407 | { |
| 408 | int rc = 0; |
| 409 | size_t sz; |
| 410 | char *name = NULL; |
| 411 | struct sgi_disklabel *sgilabel = self_disklabel(cxt); |
| 412 | |
| 413 | fdisk_info(cxt, _("The current boot file is: %s"), sgilabel->boot_file); |
| 414 | |
| 415 | rc = fdisk_ask_string(cxt, _("Enter of the new boot file"), &name); |
| 416 | if (rc == 0) |
| 417 | rc = sgi_check_bootfile(cxt, name); |
| 418 | if (rc) { |
| 419 | if (rc == 1) |
| 420 | fdisk_info(cxt, _("Boot file is unchanged.")); |
| 421 | goto done; |
| 422 | } |
| 423 | |
| 424 | memset(sgilabel->boot_file, 0, sizeof(sgilabel->boot_file)); |
| 425 | sz = strlen(name); |
| 426 | |
| 427 | assert(sz <= sizeof(sgilabel->boot_file)); /* see sgi_check_bootfile() */ |
| 428 | |
| 429 | memcpy(sgilabel->boot_file, name, sz); |
| 430 | |
| 431 | fdisk_info(cxt, _("Bootfile has been changed to \"%s\"."), name); |
| 432 | done: |
| 433 | free(name); |
| 434 | return rc; |
| 435 | } |
| 436 | |
| 437 | static int sgi_write_disklabel(struct fdisk_context *cxt) |
| 438 | { |
| 439 | struct sgi_disklabel *sgilabel; |
| 440 | struct sgi_info *info = NULL; |
| 441 | |
| 442 | assert(cxt); |
| 443 | assert(cxt->label); |
| 444 | assert(fdisk_is_label(cxt, SGI)); |
| 445 | |
| 446 | sgilabel = self_disklabel(cxt); |
| 447 | sgilabel->csum = 0; |
| 448 | sgilabel->csum = cpu_to_be32(sgi_pt_checksum(sgilabel)); |
| 449 | |
| 450 | assert(sgi_pt_checksum(sgilabel) == 0); |
| 451 | |
| 452 | if (lseek(cxt->dev_fd, 0, SEEK_SET) < 0) |
| 453 | goto err; |
| 454 | if (write_all(cxt->dev_fd, sgilabel, DEFAULT_SECTOR_SIZE)) |
| 455 | goto err; |
| 456 | if (!strncmp((char *) sgilabel->volume[0].name, "sgilabel", 8)) { |
| 457 | /* |
| 458 | * Keep this habit of first writing the "sgilabel". |
| 459 | * I never tested whether it works without. (AN 1998-10-02) |
| 460 | */ |
| 461 | int infostartblock |
| 462 | = be32_to_cpu(sgilabel->volume[0].block_num); |
| 463 | |
| 464 | if (lseek(cxt->dev_fd, (off_t) infostartblock * |
| 465 | DEFAULT_SECTOR_SIZE, SEEK_SET) < 0) |
| 466 | goto err; |
| 467 | info = sgi_new_info(); |
| 468 | if (!info) |
| 469 | goto err; |
| 470 | if (write_all(cxt->dev_fd, info, sizeof(*info))) |
| 471 | goto err; |
| 472 | } |
| 473 | |
| 474 | sgi_free_info(info); |
| 475 | return 0; |
| 476 | err: |
| 477 | sgi_free_info(info); |
| 478 | return -errno; |
| 479 | } |
| 480 | |
| 481 | static int compare_start(struct fdisk_context *cxt, |
| 482 | const void *x, const void *y) |
| 483 | { |
| 484 | /* |
| 485 | * Sort according to start sectors and prefer the largest partition: |
| 486 | * entry zero is the entire-disk entry. |
| 487 | */ |
| 488 | unsigned int i = *(int *) x; |
| 489 | unsigned int j = *(int *) y; |
| 490 | unsigned int a = sgi_get_start_sector(cxt, i); |
| 491 | unsigned int b = sgi_get_start_sector(cxt, j); |
| 492 | unsigned int c = sgi_get_num_sectors(cxt, i); |
| 493 | unsigned int d = sgi_get_num_sectors(cxt, j); |
| 494 | |
| 495 | if (a == b) |
| 496 | return (d > c) ? 1 : (d == c) ? 0 : -1; |
| 497 | return (a > b) ? 1 : -1; |
| 498 | } |
| 499 | |
| 500 | static void generic_swap(void *a0, void *b0, int size) |
| 501 | { |
| 502 | char *a = a0, *b = b0; |
| 503 | |
| 504 | for (; size > 0; --size, a++, b++) { |
| 505 | char t = *a; |
| 506 | *a = *b; |
| 507 | *b = t; |
| 508 | } |
| 509 | } |
| 510 | |
| 511 | |
| 512 | /* heap sort, based on Matt Mackall's linux kernel version */ |
| 513 | static void sort(void *base0, size_t num, size_t size, struct fdisk_context *cxt, |
| 514 | int (*cmp_func)(struct fdisk_context *, const void *, const void *)) |
| 515 | { |
| 516 | /* pre-scale counters for performance */ |
| 517 | int i = (num/2 - 1) * size; |
| 518 | size_t n = num * size, c, r; |
| 519 | char *base = base0; |
| 520 | |
| 521 | /* heapify */ |
| 522 | for ( ; i >= 0; i -= size) { |
| 523 | for (r = i; r * 2 + size < n; r = c) { |
| 524 | c = r * 2 + size; |
| 525 | if (c < n - size && |
| 526 | cmp_func(cxt, base + c, base + c + size) < 0) |
| 527 | c += size; |
| 528 | if (cmp_func(cxt, base + r, base + c) >= 0) |
| 529 | break; |
| 530 | generic_swap(base + r, base + c, size); |
| 531 | } |
| 532 | } |
| 533 | |
| 534 | /* sort */ |
| 535 | for (i = n - size; i > 0; i -= size) { |
| 536 | generic_swap(base, base + i, size); |
| 537 | for (r = 0; r * 2 + size < (size_t) i; r = c) { |
| 538 | c = r * 2 + size; |
| 539 | if (c < i - size && |
| 540 | cmp_func(cxt, base + c, base + c + size) < 0) |
| 541 | c += size; |
| 542 | if (cmp_func(cxt, base + r, base + c) >= 0) |
| 543 | break; |
| 544 | generic_swap(base + r, base + c, size); |
| 545 | } |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | static int verify_disklabel(struct fdisk_context *cxt, int verbose) |
| 550 | { |
| 551 | int Index[SGI_MAXPARTITIONS]; /* list of valid partitions */ |
| 552 | int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */ |
| 553 | int entire = 0, i = 0; |
| 554 | unsigned int start = 0; |
| 555 | long long gap = 0; /* count unused blocks */ |
| 556 | unsigned int lastblock = sgi_get_lastblock(cxt); |
| 557 | |
| 558 | assert(cxt); |
| 559 | assert(cxt->label); |
| 560 | assert(fdisk_is_label(cxt, SGI)); |
| 561 | |
| 562 | clear_freelist(cxt); |
| 563 | memset(Index, 0, sizeof(Index)); |
| 564 | |
| 565 | for (i=0; i < SGI_MAXPARTITIONS; i++) { |
| 566 | if (sgi_get_num_sectors(cxt, i) != 0) { |
| 567 | Index[sortcount++] = i; |
| 568 | if (sgi_get_sysid(cxt, i) == SGI_TYPE_ENTIRE_DISK |
| 569 | && entire++ == 1) { |
| 570 | if (verbose) |
| 571 | fdisk_info(cxt, _("More than one entire " |
| 572 | "disk entry present.")); |
| 573 | } |
| 574 | } |
| 575 | } |
| 576 | if (sortcount == 0) { |
| 577 | if (verbose) |
| 578 | fdisk_info(cxt, _("No partitions defined.")); |
| 579 | if (lastblock) |
| 580 | add_to_freelist(cxt, 0, lastblock); |
| 581 | return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1; |
| 582 | } |
| 583 | |
| 584 | sort(Index, sortcount, sizeof(Index[0]), cxt, compare_start); |
| 585 | |
| 586 | if (sgi_get_sysid(cxt, Index[0]) == SGI_TYPE_ENTIRE_DISK) { |
| 587 | if (verbose && Index[0] != 10) |
| 588 | fdisk_info(cxt, _("IRIX likes it when partition 11 " |
| 589 | "covers the entire disk.")); |
| 590 | |
| 591 | if (verbose && sgi_get_start_sector(cxt, Index[0]) != 0) |
| 592 | fdisk_info(cxt, _("The entire disk partition should " |
| 593 | "start at block 0, not at block %d."), |
| 594 | sgi_get_start_sector(cxt, Index[0])); |
| 595 | |
| 596 | if (verbose && sgi_get_num_sectors(cxt, Index[0]) != lastblock) |
| 597 | DBG(LABEL, ul_debug( |
| 598 | "entire disk partition=%ds, but disk=%ds", |
| 599 | sgi_get_num_sectors(cxt, Index[0]), |
| 600 | lastblock)); |
| 601 | lastblock = sgi_get_num_sectors(cxt, Index[0]); |
| 602 | } else if (verbose) { |
| 603 | fdisk_info(cxt, _("Partition 11 should cover the entire disk.")); |
| 604 | DBG(LABEL, ul_debug("sysid=%d\tpartition=%d", |
| 605 | sgi_get_sysid(cxt, Index[0]), Index[0]+1)); |
| 606 | } |
| 607 | for (i=1, start=0; i<sortcount; i++) { |
| 608 | int cylsize = sgi_get_nsect(cxt) * sgi_get_ntrks(cxt); |
| 609 | |
| 610 | if (verbose && cylsize |
| 611 | && (sgi_get_start_sector(cxt, Index[i]) % cylsize) != 0) |
| 612 | DBG(LABEL, ul_debug("partition %d does not start on " |
| 613 | "cylinder boundary.", Index[i]+1)); |
| 614 | |
| 615 | if (verbose && cylsize |
| 616 | && sgi_get_num_sectors(cxt, Index[i]) % cylsize != 0) |
| 617 | DBG(LABEL, ul_debug("partition %d does not end on " |
| 618 | "cylinder boundary.", Index[i]+1)); |
| 619 | |
| 620 | /* We cannot handle several "entire disk" entries. */ |
| 621 | if (sgi_get_sysid(cxt, Index[i]) == SGI_TYPE_ENTIRE_DISK) |
| 622 | continue; |
| 623 | |
| 624 | if (start > sgi_get_start_sector(cxt, Index[i])) { |
| 625 | if (verbose) |
| 626 | fdisk_info(cxt, |
| 627 | P_("Partitions %d and %d overlap by %d sector.", |
| 628 | "Partitions %d and %d overlap by %d sectors.", |
| 629 | start - sgi_get_start_sector(cxt, Index[i])), |
| 630 | Index[i-1]+1, Index[i]+1, |
| 631 | start - sgi_get_start_sector(cxt, Index[i])); |
| 632 | if (gap > 0) gap = -gap; |
| 633 | if (gap == 0) gap = -1; |
| 634 | } |
| 635 | if (start < sgi_get_start_sector(cxt, Index[i])) { |
| 636 | if (verbose) |
| 637 | fdisk_info(cxt, |
| 638 | P_("Unused gap of %8u sector: sector %8u", |
| 639 | "Unused gap of %8u sectors: sectors %8u-%u", |
| 640 | sgi_get_start_sector(cxt, Index[i]) - start), |
| 641 | sgi_get_start_sector(cxt, Index[i]) - start, |
| 642 | start, sgi_get_start_sector(cxt, Index[i])-1); |
| 643 | gap += sgi_get_start_sector(cxt, Index[i]) - start; |
| 644 | add_to_freelist(cxt, start, |
| 645 | sgi_get_start_sector(cxt, Index[i])); |
| 646 | } |
| 647 | start = sgi_get_start_sector(cxt, Index[i]) |
| 648 | + sgi_get_num_sectors(cxt, Index[i]); |
| 649 | /* Align free space on cylinder boundary. */ |
| 650 | if (cylsize && start % cylsize) |
| 651 | start += cylsize - (start % cylsize); |
| 652 | |
| 653 | DBG(LABEL, ul_debug("%2d:%12d\t%12d\t%12d", Index[i], |
| 654 | sgi_get_start_sector(cxt, Index[i]), |
| 655 | sgi_get_num_sectors(cxt, Index[i]), |
| 656 | sgi_get_sysid(cxt, Index[i]))); |
| 657 | } |
| 658 | if (start < lastblock) { |
| 659 | if (verbose) |
| 660 | fdisk_info(cxt, P_("Unused gap of %8u sector: sector %8u", |
| 661 | "Unused gap of %8u sectors: sectors %8u-%u", |
| 662 | lastblock - start), |
| 663 | lastblock - start, start, lastblock-1); |
| 664 | gap += lastblock - start; |
| 665 | add_to_freelist(cxt, start, lastblock); |
| 666 | } |
| 667 | /* |
| 668 | * Done with arithmetics. Go for details now. |
| 669 | */ |
| 670 | if (verbose) { |
| 671 | if (sgi_get_bootpartition(cxt) < 0 |
| 672 | || !sgi_get_num_sectors(cxt, sgi_get_bootpartition(cxt))) |
| 673 | fdisk_info(cxt, _("The boot partition does not exist.")); |
| 674 | |
| 675 | if (sgi_get_swappartition(cxt) < 0 |
| 676 | || !sgi_get_num_sectors(cxt, sgi_get_swappartition(cxt))) |
| 677 | fdisk_info(cxt, _("The swap partition does not exist.")); |
| 678 | |
| 679 | else if (sgi_get_sysid(cxt, sgi_get_swappartition(cxt)) != SGI_TYPE_SWAP |
| 680 | && sgi_get_sysid(cxt, sgi_get_swappartition(cxt)) != MBR_LINUX_SWAP_PARTITION) |
| 681 | fdisk_info(cxt, _("The swap partition has no swap type.")); |
| 682 | |
| 683 | if (sgi_check_bootfile(cxt, "/unix")) |
| 684 | fdisk_info(cxt, _("You have chosen an unusual bootfile name.")); |
| 685 | } |
| 686 | |
| 687 | return (gap > 0) ? 1 : (gap == 0) ? 0 : -1; |
| 688 | } |
| 689 | |
| 690 | static int sgi_verify_disklabel(struct fdisk_context *cxt) |
| 691 | { |
| 692 | return verify_disklabel(cxt, 1); |
| 693 | } |
| 694 | |
| 695 | static int sgi_gaps(struct fdisk_context *cxt) |
| 696 | { |
| 697 | /* |
| 698 | * returned value is: |
| 699 | * = 0 : disk is properly filled to the rim |
| 700 | * < 0 : there is an overlap |
| 701 | * > 0 : there is still some vacant space |
| 702 | */ |
| 703 | return verify_disklabel(cxt, 0); |
| 704 | } |
| 705 | |
| 706 | /* Returns partition index of first entry marked as entire disk. */ |
| 707 | static int sgi_entire(struct fdisk_context *cxt) |
| 708 | { |
| 709 | size_t i; |
| 710 | |
| 711 | for (i = 0; i < SGI_MAXPARTITIONS; i++) |
| 712 | if (sgi_get_sysid(cxt, i) == SGI_TYPE_ENTIRE_DISK) |
| 713 | return i; |
| 714 | return -1; |
| 715 | } |
| 716 | |
| 717 | static int set_partition(struct fdisk_context *cxt, size_t i, |
| 718 | unsigned int start, unsigned int length, int sys) |
| 719 | { |
| 720 | struct sgi_disklabel *sgilabel; |
| 721 | |
| 722 | assert(cxt); |
| 723 | assert(cxt->label); |
| 724 | assert(fdisk_is_label(cxt, SGI)); |
| 725 | |
| 726 | sgilabel = self_disklabel(cxt); |
| 727 | sgilabel->partitions[i].type = cpu_to_be32(sys); |
| 728 | sgilabel->partitions[i].num_blocks = cpu_to_be32(length); |
| 729 | sgilabel->partitions[i].first_block = cpu_to_be32(start); |
| 730 | |
| 731 | fdisk_label_set_changed(cxt->label, 1); |
| 732 | |
| 733 | if (sgi_gaps(cxt) < 0) /* rebuild freelist */ |
| 734 | fdisk_warnx(cxt, _("Partition overlap on the disk.")); |
| 735 | if (length) { |
| 736 | struct fdisk_parttype *t = |
| 737 | fdisk_label_get_parttype_from_code(cxt->label, sys); |
| 738 | fdisk_info_new_partition(cxt, i + 1, start, start + length, t); |
| 739 | } |
| 740 | |
| 741 | return 0; |
| 742 | } |
| 743 | |
| 744 | static void sgi_set_entire(struct fdisk_context *cxt) |
| 745 | { |
| 746 | size_t n; |
| 747 | |
| 748 | for (n = 10; n < cxt->label->nparts_max; n++) { |
| 749 | if (!sgi_get_num_sectors(cxt, n)) { |
| 750 | set_partition(cxt, n, 0, sgi_get_lastblock(cxt), SGI_TYPE_ENTIRE_DISK); |
| 751 | break; |
| 752 | } |
| 753 | } |
| 754 | } |
| 755 | |
| 756 | static void sgi_set_volhdr(struct fdisk_context *cxt) |
| 757 | { |
| 758 | size_t n; |
| 759 | |
| 760 | for (n = 8; n < cxt->label->nparts_max; n++) { |
| 761 | if (!sgi_get_num_sectors(cxt, n)) { |
| 762 | /* Choose same default volume header size as IRIX fx uses. */ |
| 763 | if (4096 < sgi_get_lastblock(cxt)) |
| 764 | set_partition(cxt, n, 0, 4096, SGI_TYPE_VOLHDR); |
| 765 | break; |
| 766 | } |
| 767 | } |
| 768 | } |
| 769 | |
| 770 | static int sgi_delete_partition(struct fdisk_context *cxt, size_t partnum) |
| 771 | { |
| 772 | int rc; |
| 773 | |
| 774 | assert(cxt); |
| 775 | assert(cxt->label); |
| 776 | |
| 777 | if (partnum > cxt->label->nparts_max) |
| 778 | return -EINVAL; |
| 779 | |
| 780 | rc = set_partition(cxt, partnum, 0, 0, 0); |
| 781 | |
| 782 | cxt->label->nparts_cur = count_used_partitions(cxt); |
| 783 | |
| 784 | return rc; |
| 785 | } |
| 786 | |
| 787 | static int sgi_add_partition(struct fdisk_context *cxt, |
| 788 | struct fdisk_partition *pa, |
| 789 | size_t *partno) |
| 790 | { |
| 791 | struct fdisk_sgi_label *sgi; |
| 792 | char mesg[256]; |
| 793 | unsigned int first = 0, last = 0; |
| 794 | struct fdisk_ask *ask; |
| 795 | int sys = pa && pa->type ? pa->type->code : SGI_TYPE_XFS; |
| 796 | int rc; |
| 797 | size_t n; |
| 798 | |
| 799 | assert(cxt); |
| 800 | assert(cxt->label); |
| 801 | assert(fdisk_is_label(cxt, SGI)); |
| 802 | |
| 803 | rc = fdisk_partition_next_partno(pa, cxt, &n); |
| 804 | if (rc) |
| 805 | return rc; |
| 806 | if (n == 10) |
| 807 | sys = SGI_TYPE_ENTIRE_DISK; |
| 808 | else if (n == 8) |
| 809 | sys = 0; |
| 810 | |
| 811 | sgi = self_label(cxt); |
| 812 | |
| 813 | if (sgi_get_num_sectors(cxt, n)) { |
| 814 | fdisk_warnx(cxt, _("Partition %zu is already defined. " |
| 815 | "Delete it before re-adding it."), n + 1); |
| 816 | return -EINVAL; |
| 817 | } |
| 818 | if (!cxt->script && sgi_entire(cxt) == -1 && sys != SGI_TYPE_ENTIRE_DISK) { |
| 819 | fdisk_info(cxt, _("Attempting to generate entire disk entry automatically.")); |
| 820 | sgi_set_entire(cxt); |
| 821 | sgi_set_volhdr(cxt); |
| 822 | } |
| 823 | if (sgi_gaps(cxt) == 0 && sys != SGI_TYPE_ENTIRE_DISK) { |
| 824 | fdisk_warnx(cxt, _("The entire disk is already covered with partitions.")); |
| 825 | return -EINVAL; |
| 826 | } |
| 827 | if (sgi_gaps(cxt) < 0) { |
| 828 | fdisk_warnx(cxt, _("You got a partition overlap on the disk. Fix it first!")); |
| 829 | return -EINVAL; |
| 830 | } |
| 831 | |
| 832 | if (sys == SGI_TYPE_ENTIRE_DISK) { |
| 833 | first = 0; |
| 834 | last = sgi_get_lastblock(cxt); |
| 835 | } else { |
| 836 | first = sgi->freelist[0].first; |
| 837 | last = sgi->freelist[0].last; |
| 838 | } |
| 839 | |
| 840 | /* first sector */ |
| 841 | if (pa && pa->start_follow_default) |
| 842 | ; |
| 843 | else if (pa && fdisk_partition_has_start(pa)) { |
| 844 | first = pa->start; |
| 845 | last = is_in_freelist(cxt, first); |
| 846 | |
| 847 | if (sys != SGI_TYPE_ENTIRE_DISK && !last) |
| 848 | return -ERANGE; |
| 849 | } else { |
| 850 | snprintf(mesg, sizeof(mesg), _("First %s"), |
| 851 | fdisk_get_unit(cxt, FDISK_SINGULAR)); |
| 852 | ask = fdisk_new_ask(); |
| 853 | if (!ask) |
| 854 | return -ENOMEM; |
| 855 | |
| 856 | fdisk_ask_set_query(ask, mesg); |
| 857 | fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); |
| 858 | |
| 859 | fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ |
| 860 | fdisk_ask_number_set_default(ask, fdisk_scround(cxt, first)); /* default */ |
| 861 | fdisk_ask_number_set_high(ask, fdisk_scround(cxt, last) - 1); /* maximal */ |
| 862 | |
| 863 | rc = fdisk_do_ask(cxt, ask); |
| 864 | first = fdisk_ask_number_get_result(ask); |
| 865 | fdisk_unref_ask(ask); |
| 866 | |
| 867 | if (rc) |
| 868 | return rc; |
| 869 | if (fdisk_use_cylinders(cxt)) |
| 870 | first *= fdisk_get_units_per_sector(cxt); |
| 871 | } |
| 872 | |
| 873 | if (first && sys == SGI_TYPE_ENTIRE_DISK) |
| 874 | fdisk_info(cxt, _("It is highly recommended that the " |
| 875 | "eleventh partition covers the entire " |
| 876 | "disk and is of type 'SGI volume'.")); |
| 877 | if (!last) |
| 878 | last = is_in_freelist(cxt, first); |
| 879 | |
| 880 | /* last sector */ |
| 881 | if (pa && pa->end_follow_default) |
| 882 | last -= 1ULL; |
| 883 | else if (pa && fdisk_partition_has_size(pa)) { |
| 884 | if (first + pa->size - 1ULL > last) |
| 885 | return -ERANGE; |
| 886 | last = first + pa->size - 1ULL; |
| 887 | } else { |
| 888 | snprintf(mesg, sizeof(mesg), |
| 889 | _("Last %s or +%s or +size{K,M,G,T,P}"), |
| 890 | fdisk_get_unit(cxt, FDISK_SINGULAR), |
| 891 | fdisk_get_unit(cxt, FDISK_PLURAL)); |
| 892 | |
| 893 | ask = fdisk_new_ask(); |
| 894 | if (!ask) |
| 895 | return -ENOMEM; |
| 896 | |
| 897 | fdisk_ask_set_query(ask, mesg); |
| 898 | fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); |
| 899 | |
| 900 | fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ |
| 901 | fdisk_ask_number_set_default(ask, fdisk_scround(cxt, last) - 1);/* default */ |
| 902 | fdisk_ask_number_set_high(ask, fdisk_scround(cxt, last) - 1);/* maximal */ |
| 903 | fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first)); |
| 904 | |
| 905 | if (fdisk_use_cylinders(cxt)) |
| 906 | fdisk_ask_number_set_unit(ask, |
| 907 | cxt->sector_size * |
| 908 | fdisk_get_units_per_sector(cxt)); |
| 909 | else |
| 910 | fdisk_ask_number_set_unit(ask,cxt->sector_size); |
| 911 | |
| 912 | rc = fdisk_do_ask(cxt, ask); |
| 913 | last = fdisk_ask_number_get_result(ask) + 1; |
| 914 | |
| 915 | fdisk_unref_ask(ask); |
| 916 | if (rc) |
| 917 | return rc; |
| 918 | if (fdisk_use_cylinders(cxt)) |
| 919 | last *= fdisk_get_units_per_sector(cxt); |
| 920 | } |
| 921 | |
| 922 | if (sys == SGI_TYPE_ENTIRE_DISK |
| 923 | && (first != 0 || last != sgi_get_lastblock(cxt))) |
| 924 | fdisk_info(cxt, _("It is highly recommended that the " |
| 925 | "eleventh partition covers the entire " |
| 926 | "disk and is of type 'SGI volume'.")); |
| 927 | |
| 928 | set_partition(cxt, n, first, last - first, sys); |
| 929 | cxt->label->nparts_cur = count_used_partitions(cxt); |
| 930 | if (partno) |
| 931 | *partno = n; |
| 932 | return 0; |
| 933 | } |
| 934 | |
| 935 | static int sgi_create_disklabel(struct fdisk_context *cxt) |
| 936 | { |
| 937 | struct fdisk_sgi_label *sgi; |
| 938 | struct sgi_disklabel *sgilabel; |
| 939 | int rc; |
| 940 | |
| 941 | assert(cxt); |
| 942 | assert(cxt->label); |
| 943 | assert(fdisk_is_label(cxt, SGI)); |
| 944 | |
| 945 | #ifdef HDIO_GETGEO |
| 946 | if (cxt->geom.heads && cxt->geom.sectors) { |
| 947 | fdisk_sector_t llsectors; |
| 948 | |
| 949 | if (blkdev_get_sectors(cxt->dev_fd, (unsigned long long *) &llsectors) == 0) { |
| 950 | /* the get device size ioctl was successful */ |
| 951 | fdisk_sector_t llcyls; |
| 952 | int sec_fac = cxt->sector_size / 512; |
| 953 | |
| 954 | llcyls = llsectors / (cxt->geom.heads * cxt->geom.sectors * sec_fac); |
| 955 | cxt->geom.cylinders = llcyls; |
| 956 | if (cxt->geom.cylinders != llcyls) /* truncated? */ |
| 957 | cxt->geom.cylinders = ~0; |
| 958 | } else { |
| 959 | /* otherwise print error and use truncated version */ |
| 960 | fdisk_warnx(cxt, |
| 961 | _("BLKGETSIZE ioctl failed on %s. " |
| 962 | "Using geometry cylinder value of %llu. " |
| 963 | "This value may be truncated for devices " |
| 964 | "> 33.8 GB."), cxt->dev_path, cxt->geom.cylinders); |
| 965 | } |
| 966 | } |
| 967 | #endif |
| 968 | rc = fdisk_init_firstsector_buffer(cxt); |
| 969 | if (rc) |
| 970 | return rc; |
| 971 | |
| 972 | sgi = (struct fdisk_sgi_label *) cxt->label; |
| 973 | sgi->header = (struct sgi_disklabel *) cxt->firstsector; |
| 974 | |
| 975 | sgilabel = sgi->header; |
| 976 | |
| 977 | sgilabel->magic = cpu_to_be32(SGI_LABEL_MAGIC); |
| 978 | sgilabel->root_part_num = cpu_to_be16(0); |
| 979 | sgilabel->swap_part_num = cpu_to_be16(1); |
| 980 | |
| 981 | /* sizeof(sgilabel->boot_file) = 16 > 6 */ |
| 982 | memset(sgilabel->boot_file, 0, 16); |
| 983 | strcpy((char *) sgilabel->boot_file, "/unix"); |
| 984 | |
| 985 | sgilabel->devparam.skew = (0); |
| 986 | sgilabel->devparam.gap1 = (0); |
| 987 | sgilabel->devparam.gap2 = (0); |
| 988 | sgilabel->devparam.sparecyl = (0); |
| 989 | sgilabel->devparam.pcylcount = cpu_to_be16(cxt->geom.cylinders); |
| 990 | sgilabel->devparam.head_vol0 = cpu_to_be16(0); |
| 991 | sgilabel->devparam.ntrks = cpu_to_be16(cxt->geom.heads); |
| 992 | /* tracks/cylinder (heads) */ |
| 993 | sgilabel->devparam.cmd_tag_queue_depth = (0); |
| 994 | sgilabel->devparam.unused0 = (0); |
| 995 | sgilabel->devparam.unused1 = cpu_to_be16(0); |
| 996 | sgilabel->devparam.nsect = cpu_to_be16(cxt->geom.sectors); |
| 997 | /* sectors/track */ |
| 998 | sgilabel->devparam.bytes = cpu_to_be16(cxt->sector_size); |
| 999 | sgilabel->devparam.ilfact = cpu_to_be16(1); |
| 1000 | sgilabel->devparam.flags = cpu_to_be32( |
| 1001 | SGI_DEVPARAM_TRACK_FWD |
| 1002 | | SGI_DEVPARAM_IGNORE_ERRORS |
| 1003 | | SGI_DEVPARAM_RESEEK); |
| 1004 | sgilabel->devparam.datarate = cpu_to_be32(0); |
| 1005 | sgilabel->devparam.retries_on_error = cpu_to_be32(1); |
| 1006 | sgilabel->devparam.ms_per_word = cpu_to_be32(0); |
| 1007 | sgilabel->devparam.xylogics_gap1 = cpu_to_be16(0); |
| 1008 | sgilabel->devparam.xylogics_syncdelay = cpu_to_be16(0); |
| 1009 | sgilabel->devparam.xylogics_readdelay = cpu_to_be16(0); |
| 1010 | sgilabel->devparam.xylogics_gap2 = cpu_to_be16(0); |
| 1011 | sgilabel->devparam.xylogics_readgate = cpu_to_be16(0); |
| 1012 | sgilabel->devparam.xylogics_writecont = cpu_to_be16(0); |
| 1013 | |
| 1014 | memset(&(sgilabel->volume), 0, |
| 1015 | sizeof(struct sgi_volume) * SGI_MAXVOLUMES); |
| 1016 | memset(&(sgilabel->partitions), 0, |
| 1017 | sizeof(struct sgi_partition) * SGI_MAXPARTITIONS); |
| 1018 | cxt->label->nparts_max = SGI_MAXPARTITIONS; |
| 1019 | |
| 1020 | /* don't create default layout when a script defined */ |
| 1021 | if (!cxt->script) { |
| 1022 | sgi_set_entire(cxt); |
| 1023 | sgi_set_volhdr(cxt); |
| 1024 | } |
| 1025 | cxt->label->nparts_cur = count_used_partitions(cxt); |
| 1026 | |
| 1027 | fdisk_info(cxt, _("Created a new SGI disklabel.")); |
| 1028 | return 0; |
| 1029 | } |
| 1030 | |
| 1031 | static int sgi_set_partition(struct fdisk_context *cxt, |
| 1032 | size_t i, |
| 1033 | struct fdisk_partition *pa) |
| 1034 | { |
| 1035 | struct sgi_disklabel *sgilabel; |
| 1036 | |
| 1037 | if (i >= cxt->label->nparts_max) |
| 1038 | return -EINVAL; |
| 1039 | |
| 1040 | sgilabel = self_disklabel(cxt); |
| 1041 | |
| 1042 | if (pa->type) { |
| 1043 | struct fdisk_parttype *t = pa->type; |
| 1044 | |
| 1045 | if (t->code > UINT32_MAX) |
| 1046 | return -EINVAL; |
| 1047 | |
| 1048 | if (sgi_get_num_sectors(cxt, i) == 0) /* caught already before, ... */ { |
| 1049 | fdisk_warnx(cxt, _("Sorry, only for non-empty partitions you can change the tag.")); |
| 1050 | return -EINVAL; |
| 1051 | } |
| 1052 | |
| 1053 | if ((i == 10 && t->code != SGI_TYPE_ENTIRE_DISK) |
| 1054 | || (i == 8 && t->code != 0)) |
| 1055 | fdisk_info(cxt, _("Consider leaving partition 9 as volume header (0), " |
| 1056 | "and partition 11 as entire volume (6), " |
| 1057 | "as IRIX expects it.")); |
| 1058 | |
| 1059 | if (cxt->script == NULL |
| 1060 | && ((t->code != SGI_TYPE_ENTIRE_DISK) && (t->code != SGI_TYPE_VOLHDR)) |
| 1061 | && (sgi_get_start_sector(cxt, i) < 1)) { |
| 1062 | int yes = 0; |
| 1063 | fdisk_ask_yesno(cxt, |
| 1064 | _("It is highly recommended that the partition at offset 0 " |
| 1065 | "is of type \"SGI volhdr\", the IRIX system will rely on it to " |
| 1066 | "retrieve from its directory standalone tools like sash and fx. " |
| 1067 | "Only the \"SGI volume\" entire disk section may violate this. " |
| 1068 | "Are you sure about tagging this partition differently?"), &yes); |
| 1069 | if (!yes) |
| 1070 | return 1; |
| 1071 | } |
| 1072 | |
| 1073 | sgilabel->partitions[i].type = cpu_to_be32(t->code); |
| 1074 | } |
| 1075 | |
| 1076 | if (fdisk_partition_has_start(pa)) |
| 1077 | sgilabel->partitions[i].first_block = cpu_to_be32(pa->start); |
| 1078 | if (fdisk_partition_has_size(pa)) |
| 1079 | sgilabel->partitions[i].num_blocks = cpu_to_be32(pa->size); |
| 1080 | |
| 1081 | fdisk_label_set_changed(cxt->label, 1); |
| 1082 | return 0; |
| 1083 | } |
| 1084 | |
| 1085 | |
| 1086 | static int sgi_partition_is_used( |
| 1087 | struct fdisk_context *cxt, |
| 1088 | size_t i) |
| 1089 | { |
| 1090 | assert(cxt); |
| 1091 | assert(fdisk_is_label(cxt, SGI)); |
| 1092 | |
| 1093 | if (i >= cxt->label->nparts_max) |
| 1094 | return 0; |
| 1095 | return sgi_get_num_sectors(cxt, i) ? 1 : 0; |
| 1096 | } |
| 1097 | |
| 1098 | static int sgi_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsigned long flag) |
| 1099 | { |
| 1100 | struct sgi_disklabel *sgilabel; |
| 1101 | assert(cxt); |
| 1102 | assert(cxt->label); |
| 1103 | assert(fdisk_is_label(cxt, SGI)); |
| 1104 | |
| 1105 | if (i >= cxt->label->nparts_max) |
| 1106 | return -EINVAL; |
| 1107 | |
| 1108 | sgilabel = self_disklabel(cxt); |
| 1109 | |
| 1110 | switch (flag) { |
| 1111 | case SGI_FLAG_BOOT: |
| 1112 | sgilabel->root_part_num = |
| 1113 | be16_to_cpu(sgilabel->root_part_num) == i ? |
| 1114 | 0 : cpu_to_be16(i); |
| 1115 | fdisk_label_set_changed(cxt->label, 1); |
| 1116 | break; |
| 1117 | case SGI_FLAG_SWAP: |
| 1118 | sgilabel->swap_part_num = |
| 1119 | be16_to_cpu(sgilabel->swap_part_num) == i ? |
| 1120 | 0 : cpu_to_be16(i); |
| 1121 | fdisk_label_set_changed(cxt->label, 1); |
| 1122 | break; |
| 1123 | default: |
| 1124 | return 1; |
| 1125 | } |
| 1126 | |
| 1127 | return 0; |
| 1128 | } |
| 1129 | |
| 1130 | static const struct fdisk_field sgi_fields[] = |
| 1131 | { |
| 1132 | { FDISK_FIELD_DEVICE, N_("Device"), 10, 0 }, |
| 1133 | { FDISK_FIELD_START, N_("Start"), 5, FDISK_FIELDFL_NUMBER }, |
| 1134 | { FDISK_FIELD_END, N_("End"), 5, FDISK_FIELDFL_NUMBER }, |
| 1135 | { FDISK_FIELD_SECTORS, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER }, |
| 1136 | { FDISK_FIELD_CYLINDERS,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER }, |
| 1137 | { FDISK_FIELD_SIZE, N_("Size"), 5, FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_EYECANDY }, |
| 1138 | { FDISK_FIELD_TYPEID, N_("Id"), 2, FDISK_FIELDFL_NUMBER }, |
| 1139 | { FDISK_FIELD_TYPE, N_("Type"), 0.1, FDISK_FIELDFL_EYECANDY }, |
| 1140 | { FDISK_FIELD_ATTR, N_("Attrs"), 0, FDISK_FIELDFL_NUMBER } |
| 1141 | }; |
| 1142 | |
| 1143 | static const struct fdisk_label_operations sgi_operations = |
| 1144 | { |
| 1145 | .probe = sgi_probe_label, |
| 1146 | .write = sgi_write_disklabel, |
| 1147 | .verify = sgi_verify_disklabel, |
| 1148 | .create = sgi_create_disklabel, |
| 1149 | .list = sgi_list_table, |
| 1150 | |
| 1151 | .get_part = sgi_get_partition, |
| 1152 | .set_part = sgi_set_partition, |
| 1153 | .add_part = sgi_add_partition, |
| 1154 | .del_part = sgi_delete_partition, |
| 1155 | |
| 1156 | .part_is_used = sgi_partition_is_used, |
| 1157 | .part_toggle_flag = sgi_toggle_partition_flag |
| 1158 | }; |
| 1159 | |
| 1160 | /* Allocates an SGI label driver. */ |
| 1161 | struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt) |
| 1162 | { |
| 1163 | struct fdisk_label *lb; |
| 1164 | struct fdisk_sgi_label *sgi; |
| 1165 | |
| 1166 | assert(cxt); |
| 1167 | |
| 1168 | sgi = calloc(1, sizeof(*sgi)); |
| 1169 | if (!sgi) |
| 1170 | return NULL; |
| 1171 | |
| 1172 | /* initialize generic part of the driver */ |
| 1173 | lb = (struct fdisk_label *) sgi; |
| 1174 | lb->name = "sgi"; |
| 1175 | lb->id = FDISK_DISKLABEL_SGI; |
| 1176 | lb->op = &sgi_operations; |
| 1177 | lb->parttypes = sgi_parttypes; |
| 1178 | lb->nparttypes = ARRAY_SIZE(sgi_parttypes) - 1; |
| 1179 | lb->fields = sgi_fields; |
| 1180 | lb->nfields = ARRAY_SIZE(sgi_fields); |
| 1181 | |
| 1182 | lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY; |
| 1183 | |
| 1184 | return lb; |
| 1185 | } |