1 /* $NetBSD: partitions.h,v 1.29 2023/01/06 18:19:27 martin Exp $ */ 2 3 /* 4 * Copyright (c) 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Abstract interface to access arbitrary disk partitioning schemes and 31 * keep Sysinst proper independent of the implementation / on-disk 32 * details. 33 * 34 * NOTE: 35 * - all sector numbers, alignment and sizes are in units of the 36 * disks physical sector size (not necessarily 512 bytes)! 37 * - some interfaces pass the disks sector size (when it is easily 38 * available at typical callers), but the backends can always 39 * assume it to be equal to the real physical sector size. If 40 * no value is passed, the backend can query the disk data 41 * via get_disk_geom(). 42 * - single exception: disk_partitioning_scheme::size_limit is in 512 43 * byte sectors (as it is not associated with a concrete disk) 44 */ 45 46 #include <sys/types.h> 47 #include <stdbool.h> 48 #include "msg_defs.h" 49 50 /* 51 * Import all the file system types, as enum fs_type. 52 */ 53 #define FSTYPE_ENUMNAME fs_type 54 #define FSTYPENAMES 55 #include <sys/disklabel.h> 56 #undef FSTYPE_ENUMNAME 57 58 /* 59 * Use random values (outside uint8_t range) to mark special file system 60 * types that are not in the FSTYPE enumeration. 61 */ 62 #ifndef FS_TMPFS 63 #define FS_TMPFS 256 /* tmpfs (prefered for /tmp if available) */ 64 #endif 65 #ifndef FS_MFS 66 #define FS_MFS 257 /* mfs, alternative to tmpfs if that is 67 not available */ 68 #endif 69 #ifndef FS_EFI_SP 70 #define FS_EFI_SP 258 /* EFI system partition, uses FS_MSDOS, 71 but may have a different partition 72 type */ 73 #endif 74 75 #define MAX_LABEL_LEN 128 /* max. length of a partition label */ 76 #define MAX_SHORTCUT_LEN 8 /* max. length of a shortcut ("a:") */ 77 78 /* 79 * A partition index / handle, identifies a singlepartition within 80 * a struct disk_partitions. This is just an iterator/index - whenever 81 * changes to the set of partitions are done, partitions may get a new 82 * part_id. 83 * We assume that partitioning schemes keep partitions sorted (with 84 * key = start address, some schemes will have overlapping partitions, 85 * like MBR extended partitions). 86 */ 87 typedef size_t part_id; 88 89 /* 90 * An invalid value for a partition index / handle 91 */ 92 #define NO_PART ((part_id)~0U) 93 94 /* 95 * Intended usage for a partition 96 */ 97 enum part_type { 98 PT_undef, /* invalid value */ 99 PT_unknown, /* anything we can not map to one of these */ 100 PT_root, /* the NetBSD / partition (bootable) */ 101 PT_swap, /* the NetBSD swap partition */ 102 PT_FAT, /* boot partition (e.g. for u-boot) */ 103 PT_EXT2, /* boot partition (for Linux appliances) */ 104 PT_SYSVBFS, /* boot partition (for some SYSV machines) */ 105 PT_EFI_SYSTEM, /* (U)EFI boot partition */ 106 }; 107 108 /* 109 * A generic structure describing partition types for menu/user interface 110 * purposes. The internal details may be richer and the *pointer* value 111 * is the unique token - that is: the partitioning scheme will hand out 112 * pointers to internal data and recognize the exact partition type details 113 * by pointer comparison. 114 */ 115 struct part_type_desc { 116 enum part_type generic_ptype; /* what this maps to in generic terms */ 117 const char *short_desc; /* short type description */ 118 const char *description; /* full description */ 119 }; 120 121 /* Bits for disk_part_info.flags: */ 122 #define PTI_SEC_CONTAINER 1 /* this covers our secondary 123 partitions */ 124 #define PTI_WHOLE_DISK 2 /* all of the NetBSD disk */ 125 #define PTI_BOOT 4 /* required for booting */ 126 #define PTI_PSCHEME_INTERNAL 8 /* no user partition, e.g. 127 MBRs extend partition */ 128 #define PTI_RAW_PART 16 /* total disk */ 129 #define PTI_INSTALL_TARGET 32 /* marks the target partition 130 * assumed to become / after 131 * reboot; may not be 132 * persistent; may only be 133 * set for a single partition! 134 */ 135 #define PTI_SPECIAL_PARTS \ 136 (PTI_PSCHEME_INTERNAL|PTI_WHOLE_DISK|PTI_SEC_CONTAINER|PTI_RAW_PART) 137 138 139 /* A single partition */ 140 struct disk_part_info { 141 daddr_t start, size; /* start and size on disk */ 142 uint32_t flags; /* active PTI_ flags */ 143 const struct part_type_desc *nat_type; /* native partition type */ 144 /* 145 * The following will only be available 146 * a) for a small subset of file system types 147 * b) if the partition (in this state) has already been 148 * used before 149 * It is OK to leave all these zeroed / NULL when setting 150 * partition data - or leave them at the last values a get operation 151 * returned. Backends can not rely on them to be valid. 152 */ 153 const char *last_mounted; /* last mount point or NULL */ 154 unsigned int fs_type, fs_sub_type, /* FS_* type of filesystem 155 * and for some FS a sub 156 * type (e.g. FFSv1 vs. FFSv2) 157 */ 158 fs_opt1, fs_opt2, fs_opt3; /* FS specific option, used 159 * for FFS block/fragsize 160 * and inodes 161 */ 162 }; 163 164 /* An unused area that may be used for new partitions */ 165 struct disk_part_free_space { 166 daddr_t start, size; 167 }; 168 169 /* 170 * Some partition schemes define additional data that needs to be edited. 171 * These attributes are described in this structure and referenced by 172 * their index into the fixed list of available attributes. 173 */ 174 enum custom_attr_type { pet_bool, pet_cardinal, pet_str }; 175 struct disk_part_custom_attribute { 176 msg label; /* Name, like "active partition" */ 177 enum custom_attr_type type; /* bool, long, char* */ 178 size_t strlen; /* maximum length if pet_str */ 179 }; 180 181 /* 182 * When displaying a partition editor, we have standard columns, but 183 * partitioning schemes add custom columns to the table as well. 184 * There is a fixed number of columns and they are described by this 185 * structure: 186 */ 187 struct disk_part_edit_column_desc { 188 msg title; 189 unsigned int width; 190 }; 191 192 struct disk_partitions; /* in-memory representation of a set of partitions */ 193 194 /* 195 * When querying partition "device" names, we may ask for: 196 */ 197 enum dev_name_usage { 198 parent_device_only, /* wd0 instead of wd0i, no path */ 199 logical_name, /* NAME=my-root instead of dk7 */ 200 plain_name, /* e.g. /dev/wd0i or /dev/dk7 */ 201 raw_dev_name, /* e.g. /dev/rwd0i or /dev/rdk7 */ 202 }; 203 204 /* 205 * A scheme how to store partitions on-disk, and methods to read/write 206 * them to/from our abstract internal presentation. 207 */ 208 struct disk_partitioning_scheme { 209 /* name of the on-disk scheme, retrieved via msg_string */ 210 msg name, short_name; 211 212 /* prompt shown when creating custom partition types */ 213 msg new_type_prompt; 214 215 /* description of scheme specific partition flags */ 216 msg part_flag_desc; 217 218 /* 219 * size restrictions for this partitioning scheme (number 220 * of 512 byte sectors max) 221 */ 222 daddr_t size_limit; /* 0 if not limited */ 223 224 /* 225 * If this scheme allows sub-partitions (i.e. MBR -> disklabel), 226 * this is a pointer to the (potential/optional) secondary 227 * scheme. Depending on partitioning details it may not be 228 * used in the end. 229 * This link is only here for better help messages. 230 * See *secondary_partitions further below for actually accessing 231 * secondary partitions. 232 */ 233 const struct disk_partitioning_scheme *secondary_scheme; 234 235 /* 236 * Partition editor colum descriptions for whatever the scheme 237 * needs to display (see format_partition_table_str below). 238 */ 239 size_t edit_columns_count; 240 const struct disk_part_edit_column_desc *edit_columns; 241 242 /* 243 * Custom attributes editable by the partitioning scheme (but of 244 * no particular meaning for sysinst) 245 */ 246 size_t custom_attribute_count; 247 const struct disk_part_custom_attribute *custom_attributes; 248 249 /* 250 * Partition types supported by this scheme, 251 * first function gets the number, second queries single elements 252 */ 253 size_t (*get_part_types_count)(void); 254 const struct part_type_desc * (*get_part_type)(size_t ndx); 255 /* 256 * Get the preferred native representation for a generic partition type 257 */ 258 const struct part_type_desc * (*get_generic_part_type)(enum part_type); 259 /* 260 * Get the preferred native partition type for a specific file system 261 * type (FS_*) and subtype (fs specific value) 262 */ 263 const struct part_type_desc * (*get_fs_part_type)( 264 enum part_type, unsigned, unsigned); 265 /* 266 * Optional: inverse to above: given a part_type_desc, set default 267 * fstype and subtype. 268 */ 269 bool (*get_default_fstype)(const struct part_type_desc *, 270 unsigned *fstype, unsigned *fs_sub_type); 271 /* 272 * Create a custom partition type. If the type already exists 273 * (or there is a collision), the old existing type will be 274 * returned and no new type created. This is not considered 275 * an error (to keep the user interface simple). 276 * On failure NULL is returned and (if passed != NULL) 277 * *err_msg is set to a message describing the error. 278 */ 279 const struct part_type_desc * (*create_custom_part_type) 280 (const char *custom, const char **err_msg); 281 /* 282 * Return a usable internal partition type representation 283 * for types that are not otherwise mappable. 284 * This could be FS_OTHER for disklabel, or a randomly 285 * created type guid for GPT. This type may or may not be 286 * in the regular type list. If not, it needs to behave like a 287 * custom type. 288 */ 289 const struct part_type_desc * (*create_unknown_part_type)(void); 290 291 /* 292 * Global attributes 293 */ 294 /* 295 * Get partition alignment suggestion. The schemen may enforce 296 * additional/different alignment for some partitions. 297 */ 298 daddr_t (*get_part_alignment)(const struct disk_partitions*); 299 300 /* 301 * Methods to manipulate the in-memory abstract representation 302 */ 303 304 /* Retrieve data about a single partition, identified by the part_id. 305 * Fill the disk_part_info structure 306 */ 307 bool (*get_part_info)(const struct disk_partitions*, part_id, 308 struct disk_part_info*); 309 310 /* Optional: fill an attribute string describing the given partition */ 311 bool (*get_part_attr_str)(const struct disk_partitions*, part_id, 312 char *str, size_t avail_space); 313 /* Format a partition editor element for the "col" column in 314 * edit_columns. Used e.g. with MBR to set "active" flags. 315 */ 316 bool (*format_partition_table_str)(const struct disk_partitions*, 317 part_id, size_t col, char *outstr, size_t outspace); 318 319 /* is the type of this partition changeable? */ 320 bool (*part_type_can_change)(const struct disk_partitions*, 321 part_id); 322 323 /* can we add further partitions? */ 324 bool (*can_add_partition)(const struct disk_partitions*); 325 326 /* is the custom attribute changeable? */ 327 bool (*custom_attribute_writable)(const struct disk_partitions*, 328 part_id, size_t attr_no); 329 /* 330 * Output formatting for custom attributes. 331 * If "info" is != NULL, use (where it makes sense) 332 * values from that structure, as if a call to set_part_info 333 * would have been done before this call. 334 */ 335 bool (*format_custom_attribute)(const struct disk_partitions*, 336 part_id, size_t attr_no, const struct disk_part_info *info, 337 char *out, size_t out_space); 338 /* value setter functions for custom attributes */ 339 /* pet_bool: */ 340 bool (*custom_attribute_toggle)(struct disk_partitions*, 341 part_id, size_t attr_no); 342 /* pet_cardinal: */ 343 bool (*custom_attribute_set_card)(struct disk_partitions*, 344 part_id, size_t attr_no, long new_val); 345 /* pet_str or pet_cardinal: */ 346 bool (*custom_attribute_set_str)(struct disk_partitions*, 347 part_id, size_t attr_no, const char *new_val); 348 349 /* 350 * Optional: additional user information when showing the size 351 * editor (especially for existing unknown partitions) 352 */ 353 const char * (*other_partition_identifier)(const struct 354 disk_partitions*, part_id); 355 356 357 /* Retrieve device and partition names, e.g. for checking 358 * against kern.root_device or invoking newfs. 359 * For disklabel partitions, "part" will be set to the partition 360 * index (a = 0, b = 1, ...), for others it will get set to -1. 361 * If dev_name_usage is parent_device_only, the device name will 362 * not include a partition letter - obviously this only makes a 363 * difference with disklabel partitions. 364 * If dev_name_usage is logical_name instead of a device name 365 * a given name may be returned in NAME= syntax. 366 * If with_path is true (and the returned value is a device 367 * node), include the /dev/ prefix in the result string 368 * (this is ignored when returning NAME= syntax for /etc/fstab). 369 * If life is true, the device must be made available under 370 * that name (only makes a difference for NAME=syntax if 371 * no wedge has been created yet,) - implied for all variants 372 * where dev_name_usage != logical_name. 373 */ 374 bool (*get_part_device)(const struct disk_partitions*, 375 part_id, char *devname, size_t max_devname_len, int *part, 376 enum dev_name_usage, bool with_path, bool life); 377 378 /* 379 * How big could we resize the given position (start of existing 380 * partition or free space) 381 */ 382 daddr_t (*max_free_space_at)(const struct disk_partitions*, daddr_t); 383 384 /* 385 * Provide a list of free spaces usable for further partitioning, 386 * assuming the given partition alignment. 387 * If start is > 0 no space with lower sector numbers will 388 * be found. 389 * If ignore is > 0, any partition starting at that sector will 390 * be considered "free", this is used e.g. when moving an existing 391 * partition around. 392 */ 393 size_t (*get_free_spaces)(const struct disk_partitions*, 394 struct disk_part_free_space *result, size_t max_num_result, 395 daddr_t min_space_size, daddr_t align, daddr_t start, 396 daddr_t ignore /* -1 */); 397 398 /* 399 * Translate a partition description from a foreign partitioning 400 * scheme as close as possible to what we can handle in add_partition. 401 * This mostly adjusts flags and partition type pointers (using 402 * more lose matching than add_partition would do). 403 */ 404 bool (*adapt_foreign_part_info)( 405 const struct disk_partitions *myself, struct disk_part_info *dest, 406 const struct disk_partitioning_scheme *src_scheme, 407 const struct disk_part_info *src); 408 409 /* 410 * Update data for an existing partition 411 */ 412 bool (*set_part_info)(struct disk_partitions*, part_id, 413 const struct disk_part_info*, const char **err_msg); 414 415 /* Add a new partition and return its part_id. */ 416 part_id (*add_partition)(struct disk_partitions*, 417 const struct disk_part_info*, const char **err_msg); 418 419 /* 420 * Optional: add a partition from an outer scheme, accept all 421 * details w/o verification as best as possible. 422 */ 423 part_id (*add_outer_partition)(struct disk_partitions*, 424 const struct disk_part_info*, const char **err_msg); 425 426 /* Delete all partitions */ 427 bool (*delete_all_partitions)(struct disk_partitions*); 428 429 /* Optional: delete any partitions inside the given range */ 430 bool (*delete_partitions_in_range)(struct disk_partitions*, 431 daddr_t start, daddr_t size); 432 433 /* Delete the specified partition */ 434 bool (*delete_partition)(struct disk_partitions*, part_id, 435 const char **err_msg); 436 437 /* 438 * Methods for the whole set of partitions 439 */ 440 /* 441 * If this scheme only creates a singly NetBSD partition, which 442 * then is sub-partitioned (usually by disklabel), this returns a 443 * pointer to the secondary partition set. 444 * Otherwise NULL is returned, e.g. when there is no 445 * NetBSD partition defined (so this might change over time). 446 * Schemes that NEVER use a secondary scheme set this 447 * function pointer to NULL. 448 * 449 * If force_empty = true, ignore all on-disk contents and just 450 * create a new disk_partitions structure for the secondary scheme 451 * (this is used after deleting all partitions and setting up 452 * things for "use whole disk"). 453 * 454 * The returned pointer is always owned by the primary partitions, 455 * caller MUST never free it, but otherwise can manipulate it 456 * arbitrarily. 457 */ 458 struct disk_partitions * 459 (*secondary_partitions)(struct disk_partitions *, daddr_t start, 460 bool force_empty); 461 462 /* 463 * Write the whole set (in new_state) back to disk. 464 */ 465 bool (*write_to_disk)(struct disk_partitions *new_state); 466 467 /* 468 * Try to read partitions from a disk, return NULL if this is not 469 * the partitioning scheme in use on that device. 470 * Usually start and len are 0 (and ignored). 471 * If this is about a part of a disk (like only the NetBSD 472 * MBR partition, start and len are the valid part of the 473 * disk. 474 */ 475 struct disk_partitions * (*read_from_disk)(const char *, 476 daddr_t start, daddr_t len, size_t bytes_per_sec, 477 const struct disk_partitioning_scheme *); 478 479 /* 480 * Set up all internal data for a new disk. 481 */ 482 struct disk_partitions * (*create_new_for_disk)(const char *, 483 daddr_t start, daddr_t len, bool is_boot_drive, 484 struct disk_partitions *parent); 485 486 /* 487 * Optional: this scheme may be used to boot from the given disk 488 */ 489 bool (*have_boot_support)(const char *disk); 490 491 /* 492 * Optional: try to guess disk geometry from the partition information 493 */ 494 int (*guess_disk_geom)(struct disk_partitions *, 495 int *cyl, int *head, int *sec); 496 497 /* 498 * Return a "cylinder size" (in number of blocks) - whatever that 499 * means to a particular partitioning scheme. 500 */ 501 size_t (*get_cylinder_size)(const struct disk_partitions *); 502 503 /* 504 * Optional: change used geometry info and update internal state 505 */ 506 bool (*change_disk_geom)(struct disk_partitions *, 507 int cyl, int head, int sec); 508 509 /* 510 * Optional: 511 * Get or set a name for the whole disk (most partitioning 512 * schemes do not provide this). Used for disklabel "pack names", 513 * which then may be used for aut-discovery of wedges, so it 514 * makes sense for the user to edit them. 515 */ 516 bool (*get_disk_pack_name)(const struct disk_partitions *, 517 char *, size_t); 518 bool (*set_disk_pack_name)(struct disk_partitions *, const char *); 519 520 /* 521 * Optional: 522 * Find a partition by name (as used in /etc/fstab NAME= entries) 523 */ 524 part_id (*find_by_name)(struct disk_partitions *, const char *name); 525 526 /* 527 * Optional: 528 * Try to guess install target partition from internal data, 529 * returns true if a safe match was found and sets start/size 530 * to the target partition. 531 */ 532 bool (*guess_install_target)(const struct disk_partitions *, 533 daddr_t *start, daddr_t *size); 534 535 /* 536 * Optional: verify that the whole set of partitions would be bootable, 537 * fix up any issues (with user interaction) where needed. 538 * If "quiet" is true, fix up everything silently if possible 539 * and never return 1. 540 * Returns: 541 * 0: abort install 542 * 1: re-edit partitions 543 * 2: use anyway (continue) 544 */ 545 int (*post_edit_verify)(struct disk_partitions *, bool quiet); 546 547 /* 548 * Optional: called during updates, before mounting the target disk(s), 549 * before md_pre_update() is called. Can be used to fixup 550 * partition info for historic errors (e.g. i386 changing MBR 551 * partition type from 165 to 169), similar to post_edit_verify. 552 * Returns: 553 * true if the partition info has changed (write back required) 554 * false if nothing further needs to be done. 555 */ 556 bool (*pre_update_verify)(struct disk_partitions *); 557 558 /* Free all the data */ 559 void (*free)(struct disk_partitions*); 560 561 /* Wipe all on-disk state, leave blank disk - and free data */ 562 void (*destroy_part_scheme)(struct disk_partitions*); 563 564 /* Scheme global cleanup */ 565 void (*cleanup)(void); 566 }; 567 568 /* 569 * The in-memory representation of all partitions on a concrete disk, 570 * tied to the partitioning scheme in use. 571 * 572 * Concrete schemes will derive from the abstract disk_partitions 573 * structure (by aggregation), but consumers of the API will only 574 * ever see this public part. 575 */ 576 struct disk_partitions { 577 /* which partitioning scheme is in use */ 578 const struct disk_partitioning_scheme *pscheme; 579 580 /* the disk device this came from (or should go to) */ 581 const char *disk; 582 583 /* global/public disk data */ 584 585 /* 586 * The basic unit of size used for this disk (all "start", 587 * "size" and "align" values are in this unit). 588 */ 589 size_t bytes_per_sector; /* must be 2^n and >= 512 */ 590 591 /* 592 * Valid partitions may have IDs in the range 0 .. num_part (excl.) 593 */ 594 part_id num_part; 595 596 /* 597 * If this is a sub-partitioning, the start of the "disk" is 598 * some arbitrary partition in the parent. Sometimes we need 599 * to be able to calculate absoluted offsets. 600 */ 601 daddr_t disk_start; 602 /* 603 * Total size of the disk (usable for partitioning) 604 */ 605 daddr_t disk_size; 606 607 /* 608 * Space not yet allocated 609 */ 610 daddr_t free_space; 611 612 /* 613 * If this is the secondary partitioning scheme, pointer to 614 * the outer one. Otherwise NULL. 615 */ 616 struct disk_partitions *parent; 617 }; 618 619 /* 620 * A list of partitioning schemes, so we can iterate over everything 621 * supported (e.g. when partitioning a new disk). NULL terminated. 622 */ 623 extern const struct disk_partitioning_scheme **available_part_schemes; 624 extern size_t num_available_part_schemes; 625 626 /* 627 * Generic reader - query a disk device and read all partitions from it 628 */ 629 struct disk_partitions * 630 partitions_read_disk(const char *, daddr_t disk_size, 631 size_t bytes_per_sector, bool no_mbr); 632 633 /* 634 * Generic part info adaption, may be overridden by individual partitioning 635 * schemes 636 */ 637 bool generic_adapt_foreign_part_info( 638 const struct disk_partitions *myself, struct disk_part_info *dest, 639 const struct disk_partitioning_scheme *src_scheme, 640 const struct disk_part_info *src); 641 642 /* 643 * One time initialization and cleanup 644 */ 645 void partitions_init(void); 646 void partitions_cleanup(void); 647 648