1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- 2 3 libparted - a library for manipulating disk partitions 4 Copyright (C) 2000, 2001, 2007 Free Software Foundation, Inc. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 19 Contributor: Matt Wilson <msw@redhat.com> 20 */ 21 22 #include <config.h> 23 24 #include <parted/parted.h> 25 #include <parted/debug.h> 26 #include <parted/endian.h> 27 28 #if ENABLE_NLS 29 # include <libintl.h> 30 # define _(String) dgettext (PACKAGE, String) 31 #else 32 # define _(String) (String) 33 #endif /* ENABLE_NLS */ 34 35 /* struct's & #define's stolen from libfdisk, which probably came from 36 * Linux... 37 */ 38 39 #define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */ 40 #define BSD_MAXPARTITIONS 8 41 #define BSD_FS_UNUSED 0 /* disklabel unused partition entry ID */ 42 #define BSD_LABEL_OFFSET 64 43 44 #define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */ 45 #define BSD_DTYPE_MSCP 2 /* MSCP */ 46 #define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */ 47 #define BSD_DTYPE_SCSI 4 /* SCSI */ 48 #define BSD_DTYPE_ESDI 5 /* ESDI interface */ 49 #define BSD_DTYPE_ST506 6 /* ST506 etc. */ 50 #define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */ 51 #define BSD_DTYPE_HPFL 8 /* HP Fiber-link */ 52 #define BSD_DTYPE_FLOPPY 10 /* floppy */ 53 54 #define BSD_BBSIZE 8192 /* size of boot area, with label */ 55 #define BSD_SBSIZE 8192 /* max size of fs superblock */ 56 57 typedef struct _BSDRawPartition BSDRawPartition; 58 typedef struct _BSDRawLabel BSDRawLabel; 59 60 #ifdef __sun 61 #define __attribute__(X) /*nothing*/ 62 #endif /* __sun */ 63 64 #ifdef __sun 65 #pragma pack(1) 66 #endif 67 struct _BSDRawPartition { /* the partition table */ 68 uint32_t p_size; /* number of sectors in partition */ 69 uint32_t p_offset; /* starting sector */ 70 uint32_t p_fsize; /* file system basic fragment size */ 71 uint8_t p_fstype; /* file system type, see below */ 72 uint8_t p_frag; /* file system fragments per block */ 73 uint16_t p_cpg; /* file system cylinders per group */ 74 } __attribute__((packed)); 75 #ifdef __sun 76 #pragma pack() 77 #endif 78 79 #ifdef __sun 80 #pragma pack(1) 81 #endif 82 struct _BSDRawLabel { 83 uint32_t d_magic; /* the magic number */ 84 int16_t d_type; /* drive type */ 85 int16_t d_subtype; /* controller/d_type specific */ 86 int8_t d_typename[16]; /* type name, e.g. "eagle" */ 87 int8_t d_packname[16]; /* pack identifier */ 88 uint32_t d_secsize; /* # of bytes per sector */ 89 uint32_t d_nsectors; /* # of data sectors per track */ 90 uint32_t d_ntracks; /* # of tracks per cylinder */ 91 uint32_t d_ncylinders; /* # of data cylinders per unit */ 92 uint32_t d_secpercyl; /* # of data sectors per cylinder */ 93 uint32_t d_secperunit; /* # of data sectors per unit */ 94 uint16_t d_sparespertrack; /* # of spare sectors per track */ 95 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */ 96 uint32_t d_acylinders; /* # of alt. cylinders per unit */ 97 uint16_t d_rpm; /* rotational speed */ 98 uint16_t d_interleave; /* hardware sector interleave */ 99 uint16_t d_trackskew; /* sector 0 skew, per track */ 100 uint16_t d_cylskew; /* sector 0 skew, per cylinder */ 101 uint32_t d_headswitch; /* head switch time, usec */ 102 uint32_t d_trkseek; /* track-to-track seek, usec */ 103 uint32_t d_flags; /* generic flags */ 104 #define NDDATA 5 105 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */ 106 #define NSPARE 5 107 uint32_t d_spare[NSPARE]; /* reserved for future use */ 108 uint32_t d_magic2; /* the magic number (again) */ 109 uint16_t d_checksum; /* xor of data incl. partitions */ 110 111 /* file system and partition information: */ 112 uint16_t d_npartitions; /* number of partitions in following */ 113 uint32_t d_bbsize; /* size of boot area at sn0, bytes */ 114 uint32_t d_sbsize; /* max size of fs superblock, bytes */ 115 BSDRawPartition d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ 116 } __attribute__((packed)); 117 #ifdef __sun 118 #pragma pack() 119 #endif 120 121 typedef struct { 122 char boot_code [512]; 123 } BSDDiskData; 124 125 typedef struct { 126 uint8_t type; 127 } BSDPartitionData; 128 129 static PedDiskType bsd_disk_type; 130 131 /* XXX fixme: endian? */ 132 static unsigned short 133 xbsd_dkcksum (BSDRawLabel *lp) { 134 unsigned short *start, *end; 135 unsigned short sum = 0; 136 137 lp->d_checksum = 0; 138 start = (u_short*) lp; 139 end = (u_short*) &lp->d_partitions [ 140 PED_LE16_TO_CPU (lp->d_npartitions)]; 141 while (start < end) 142 sum ^= *start++; 143 return sum; 144 } 145 146 /* XXX fixme: endian? */ 147 static void 148 alpha_bootblock_checksum (char *boot) { 149 uint64_t *dp, sum; 150 int i; 151 152 dp = (uint64_t *)boot; 153 sum = 0; 154 for (i = 0; i < 63; i++) 155 sum += dp[i]; 156 dp[63] = sum; 157 } 158 159 160 static int 161 bsd_probe (const PedDevice *dev) 162 { 163 char boot[512]; 164 BSDRawLabel *label; 165 166 PED_ASSERT (dev != NULL, return 0); 167 168 if (dev->sector_size != 512) 169 return 0; 170 171 if (!ped_device_read (dev, boot, 0, 1)) 172 return 0; 173 174 label = (BSDRawLabel *) (boot + BSD_LABEL_OFFSET); 175 176 alpha_bootblock_checksum(boot); 177 178 /* check magic */ 179 if (PED_LE32_TO_CPU (label->d_magic) != BSD_DISKMAGIC) 180 return 0; 181 182 return 1; 183 } 184 185 static PedDisk* 186 bsd_alloc (const PedDevice* dev) 187 { 188 PedDisk* disk; 189 BSDDiskData* bsd_specific; 190 BSDRawLabel* label; 191 192 PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0); 193 194 disk = _ped_disk_alloc ((PedDevice*)dev, &bsd_disk_type); 195 if (!disk) 196 goto error; 197 disk->disk_specific = bsd_specific = ped_malloc (sizeof (BSDDiskData)); 198 if (!bsd_specific) 199 goto error_free_disk; 200 /* Initialize the first byte to zero, so that the code in bsd_write 201 knows to call _probe_and_add_boot_code. Initializing all of the 202 remaining buffer is a little wasteful, but the alternative is to 203 figure out why a block at offset 340 would otherwise be used 204 uninitialized. */ 205 memset(bsd_specific->boot_code, 0, sizeof (bsd_specific->boot_code)); 206 207 label = (BSDRawLabel*) (bsd_specific->boot_code + BSD_LABEL_OFFSET); 208 209 label->d_magic = PED_CPU_TO_LE32 (BSD_DISKMAGIC); 210 label->d_type = PED_CPU_TO_LE16 (BSD_DTYPE_SCSI); 211 label->d_flags = 0; 212 label->d_secsize = PED_CPU_TO_LE16 (dev->sector_size); 213 label->d_nsectors = PED_CPU_TO_LE32 (dev->bios_geom.sectors); 214 label->d_ntracks = PED_CPU_TO_LE32 (dev->bios_geom.heads); 215 label->d_ncylinders = PED_CPU_TO_LE32 (dev->bios_geom.cylinders); 216 label->d_secpercyl = PED_CPU_TO_LE32 (dev->bios_geom.sectors 217 * dev->bios_geom.heads); 218 label->d_secperunit 219 = PED_CPU_TO_LE32 (dev->bios_geom.sectors 220 * dev->bios_geom.heads 221 * dev->bios_geom.cylinders); 222 223 label->d_rpm = PED_CPU_TO_LE16 (3600); 224 label->d_interleave = PED_CPU_TO_LE16 (1);; 225 label->d_trackskew = 0; 226 label->d_cylskew = 0; 227 label->d_headswitch = 0; 228 label->d_trkseek = 0; 229 230 label->d_magic2 = PED_CPU_TO_LE32 (BSD_DISKMAGIC); 231 label->d_bbsize = PED_CPU_TO_LE32 (BSD_BBSIZE); 232 label->d_sbsize = PED_CPU_TO_LE32 (BSD_SBSIZE); 233 234 label->d_npartitions = 0; 235 label->d_checksum = xbsd_dkcksum (label); 236 return disk; 237 238 error_free_disk: 239 ped_free (disk); 240 error: 241 return NULL; 242 } 243 244 static PedDisk* 245 bsd_duplicate (const PedDisk* disk) 246 { 247 PedDisk* new_disk; 248 BSDDiskData* new_bsd_data; 249 BSDDiskData* old_bsd_data = (BSDDiskData*) disk->disk_specific; 250 251 new_disk = ped_disk_new_fresh (disk->dev, &bsd_disk_type); 252 if (!new_disk) 253 return NULL; 254 255 new_bsd_data = (BSDDiskData*) new_disk->disk_specific; 256 memcpy (new_bsd_data->boot_code, old_bsd_data->boot_code, 512); 257 return new_disk; 258 } 259 260 static void 261 bsd_free (PedDisk* disk) 262 { 263 ped_free (disk->disk_specific); 264 _ped_disk_free (disk); 265 } 266 267 #ifndef DISCOVER_ONLY 268 static int 269 bsd_clobber (PedDevice* dev) 270 { 271 char boot [512]; 272 BSDRawLabel* label = (BSDRawLabel *) (boot + BSD_LABEL_OFFSET); 273 274 if (!ped_device_read (dev, boot, 0, 1)) 275 return 0; 276 label->d_magic = 0; 277 return ped_device_write (dev, (void*) boot, 0, 1); 278 } 279 #endif /* !DISCOVER_ONLY */ 280 281 static int 282 bsd_read (PedDisk* disk) 283 { 284 BSDDiskData* bsd_specific = (BSDDiskData*) disk->disk_specific; 285 BSDRawLabel* label; 286 int i; 287 288 ped_disk_delete_all (disk); 289 290 if (!ped_device_read (disk->dev, bsd_specific->boot_code, 0, 1)) 291 goto error; 292 label = (BSDRawLabel *) (bsd_specific->boot_code + BSD_LABEL_OFFSET); 293 294 for (i = 1; i <= BSD_MAXPARTITIONS; i++) { 295 PedPartition* part; 296 BSDPartitionData* bsd_part_data; 297 PedSector start; 298 PedSector end; 299 PedConstraint* constraint_exact; 300 301 if (!label->d_partitions[i - 1].p_size 302 || !label->d_partitions[i - 1].p_fstype) 303 continue; 304 start = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset); 305 end = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset) 306 + PED_LE32_TO_CPU(label->d_partitions[i - 1].p_size) - 1; 307 part = ped_partition_new (disk, 0, NULL, start, end); 308 if (!part) 309 goto error; 310 bsd_part_data = part->disk_specific; 311 bsd_part_data->type = label->d_partitions[i - 1].p_fstype; 312 part->num = i; 313 part->fs_type = ped_file_system_probe (&part->geom); 314 315 constraint_exact = ped_constraint_exact (&part->geom); 316 if (!ped_disk_add_partition (disk, part, constraint_exact)) 317 goto error; 318 ped_constraint_destroy (constraint_exact); 319 } 320 321 return 1; 322 323 error: 324 return 0; 325 } 326 327 static void 328 _probe_and_add_boot_code (const PedDisk* disk) 329 { 330 BSDDiskData* bsd_specific; 331 BSDRawLabel* old_label; 332 char old_boot_code [512]; 333 334 bsd_specific = (BSDDiskData*) disk->disk_specific; 335 old_label = (BSDRawLabel*) (old_boot_code + BSD_LABEL_OFFSET); 336 337 if (!ped_device_read (disk->dev, old_boot_code, 0, 1)) 338 return; 339 if (old_boot_code [0] 340 && old_label->d_magic == PED_CPU_TO_LE32 (BSD_DISKMAGIC)) 341 memcpy (bsd_specific->boot_code, old_boot_code, 512); 342 } 343 344 #ifndef DISCOVER_ONLY 345 static int 346 bsd_write (const PedDisk* disk) 347 { 348 BSDDiskData* bsd_specific; 349 BSDRawLabel* label; 350 BSDPartitionData* bsd_data; 351 PedPartition* part; 352 int i; 353 int max_part = 0; 354 355 PED_ASSERT (disk != NULL, return 0); 356 PED_ASSERT (disk->dev != NULL, return 0); 357 358 bsd_specific = (BSDDiskData*) disk->disk_specific; 359 label = (BSDRawLabel *) (bsd_specific->boot_code + BSD_LABEL_OFFSET); 360 361 if (!bsd_specific->boot_code [0]) 362 _probe_and_add_boot_code (disk); 363 364 memset (label->d_partitions, 0, 365 sizeof (BSDRawPartition) * BSD_MAXPARTITIONS); 366 367 for (i = 1; i <= BSD_MAXPARTITIONS; i++) { 368 part = ped_disk_get_partition (disk, i); 369 if (!part) 370 continue; 371 bsd_data = part->disk_specific; 372 label->d_partitions[i - 1].p_fstype = bsd_data->type; 373 label->d_partitions[i - 1].p_offset 374 = PED_CPU_TO_LE32 (part->geom.start); 375 label->d_partitions[i - 1].p_size 376 = PED_CPU_TO_LE32 (part->geom.length); 377 max_part = i; 378 } 379 380 label->d_npartitions = PED_CPU_TO_LE16 (max_part) + 1; 381 label->d_checksum = xbsd_dkcksum (label); 382 383 alpha_bootblock_checksum (bsd_specific->boot_code); 384 385 if (!ped_device_write (disk->dev, (void*) bsd_specific->boot_code, 386 0, 1)) 387 goto error; 388 return ped_device_sync (disk->dev); 389 390 error: 391 return 0; 392 } 393 #endif /* !DISCOVER_ONLY */ 394 395 static PedPartition* 396 bsd_partition_new (const PedDisk* disk, PedPartitionType part_type, 397 const PedFileSystemType* fs_type, 398 PedSector start, PedSector end) 399 { 400 PedPartition* part; 401 BSDPartitionData* bsd_data; 402 403 part = _ped_partition_alloc (disk, part_type, fs_type, start, end); 404 if (!part) 405 goto error; 406 407 if (ped_partition_is_active (part)) { 408 part->disk_specific 409 = bsd_data = ped_malloc (sizeof (BSDPartitionData)); 410 if (!bsd_data) 411 goto error_free_part; 412 bsd_data->type = 0; 413 } else { 414 part->disk_specific = NULL; 415 } 416 return part; 417 418 ped_free (bsd_data); 419 error_free_part: 420 ped_free (part); 421 error: 422 return 0; 423 } 424 425 static PedPartition* 426 bsd_partition_duplicate (const PedPartition* part) 427 { 428 PedPartition* new_part; 429 BSDPartitionData* new_bsd_data; 430 BSDPartitionData* old_bsd_data; 431 432 new_part = ped_partition_new (part->disk, part->type, 433 part->fs_type, part->geom.start, 434 part->geom.end); 435 if (!new_part) 436 return NULL; 437 new_part->num = part->num; 438 439 old_bsd_data = (BSDPartitionData*) part->disk_specific; 440 new_bsd_data = (BSDPartitionData*) new_part->disk_specific; 441 new_bsd_data->type = old_bsd_data->type; 442 return new_part; 443 } 444 445 static void 446 bsd_partition_destroy (PedPartition* part) 447 { 448 PED_ASSERT (part != NULL, return); 449 450 if (ped_partition_is_active (part)) 451 ped_free (part->disk_specific); 452 _ped_partition_free (part); 453 } 454 455 static int 456 bsd_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type) 457 { 458 BSDPartitionData* bsd_data = part->disk_specific; 459 460 part->fs_type = fs_type; 461 462 if (!fs_type) 463 bsd_data->type = 0x8; 464 else if (!strcmp (fs_type->name, "linux-swap")) 465 bsd_data->type = 0x1; 466 else 467 bsd_data->type = 0x8; 468 469 return 1; 470 } 471 472 static int 473 bsd_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state) 474 { 475 /* no flags for bsd */ 476 return 0; 477 } 478 479 static int 480 bsd_partition_get_flag (const PedPartition* part, PedPartitionFlag flag) 481 { 482 /* no flags for bsd */ 483 return 0; 484 } 485 486 static int 487 bsd_partition_is_flag_available (const PedPartition* part, 488 PedPartitionFlag flag) 489 { 490 /* no flags for bsd */ 491 return 0; 492 } 493 494 495 static int 496 bsd_get_max_primary_partition_count (const PedDisk* disk) 497 { 498 return BSD_MAXPARTITIONS; 499 } 500 501 static PedConstraint* 502 _get_constraint (const PedDevice* dev) 503 { 504 PedGeometry max; 505 506 ped_geometry_init (&max, dev, 1, dev->length - 1); 507 return ped_constraint_new_from_max (&max); 508 } 509 510 static int 511 bsd_partition_align (PedPartition* part, const PedConstraint* constraint) 512 { 513 if (_ped_partition_attempt_align (part, constraint, 514 _get_constraint (part->disk->dev))) 515 return 1; 516 517 #ifndef DISCOVER_ONLY 518 ped_exception_throw ( 519 PED_EXCEPTION_ERROR, 520 PED_EXCEPTION_CANCEL, 521 _("Unable to satisfy all constraints on the partition.")); 522 #endif 523 return 0; 524 } 525 526 static int 527 bsd_partition_enumerate (PedPartition* part) 528 { 529 int i; 530 PedPartition* p; 531 532 /* never change the partition numbers */ 533 if (part->num != -1) 534 return 1; 535 for (i = 1; i <= BSD_MAXPARTITIONS; i++) { 536 p = ped_disk_get_partition (part->disk, i); 537 if (!p) { 538 part->num = i; 539 return 1; 540 } 541 } 542 543 /* failed to allocate a number */ 544 #ifndef DISCOVER_ONLY 545 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 546 _("Unable to allocate a bsd disklabel slot.")); 547 #endif 548 return 0; 549 } 550 551 static int 552 bsd_alloc_metadata (PedDisk* disk) 553 { 554 PedPartition* new_part; 555 PedConstraint* constraint_any = NULL; 556 557 PED_ASSERT (disk != NULL, goto error); 558 PED_ASSERT (disk->dev != NULL, goto error); 559 560 constraint_any = ped_constraint_any (disk->dev); 561 562 /* allocate 1 sector for the disk label at the start */ 563 new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, 0, 0); 564 if (!new_part) 565 goto error; 566 567 if (!ped_disk_add_partition (disk, new_part, constraint_any)) { 568 ped_partition_destroy (new_part); 569 goto error; 570 } 571 572 ped_constraint_destroy (constraint_any); 573 return 1; 574 error: 575 ped_constraint_destroy (constraint_any); 576 return 0; 577 } 578 579 static PedDiskOps bsd_disk_ops = { 580 .probe = bsd_probe, 581 #ifndef DISCOVER_ONLY 582 .clobber = bsd_clobber, 583 #else 584 .clobber = NULL, 585 #endif 586 .alloc = bsd_alloc, 587 .duplicate = bsd_duplicate, 588 .free = bsd_free, 589 .read = bsd_read, 590 #ifndef DISCOVER_ONLY 591 .write = bsd_write, 592 #else 593 .write = NULL, 594 #endif 595 596 .partition_new = bsd_partition_new, 597 .partition_duplicate = bsd_partition_duplicate, 598 .partition_destroy = bsd_partition_destroy, 599 .partition_set_system = bsd_partition_set_system, 600 .partition_set_flag = bsd_partition_set_flag, 601 .partition_get_flag = bsd_partition_get_flag, 602 .partition_is_flag_available = bsd_partition_is_flag_available, 603 .partition_set_name = NULL, 604 .partition_get_name = NULL, 605 .partition_align = bsd_partition_align, 606 .partition_enumerate = bsd_partition_enumerate, 607 608 .alloc_metadata = bsd_alloc_metadata, 609 .get_max_primary_partition_count = 610 bsd_get_max_primary_partition_count 611 }; 612 613 static PedDiskType bsd_disk_type = { 614 .next = NULL, 615 .name = "bsd", 616 .ops = &bsd_disk_ops, 617 .features = 0 618 }; 619 620 void 621 ped_disk_bsd_init () 622 { 623 PED_ASSERT (sizeof (BSDRawPartition) == 16, return); 624 PED_ASSERT (sizeof (BSDRawLabel) == 276, return); 625 626 ped_disk_type_register (&bsd_disk_type); 627 } 628 629 void 630 ped_disk_bsd_done () 631 { 632 ped_disk_type_unregister (&bsd_disk_type); 633 }