1 /* $NetBSD: partitions.h,v 1.28 2022/06/09 18:26:06 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 136 /* A single partition */ 137 struct disk_part_info { 138 daddr_t start, size; /* start and size on disk */ 139 uint32_t flags; /* active PTI_ flags */ 140 const struct part_type_desc *nat_type; /* native partition type */ 141 /* 142 * The following will only be available 143 * a) for a small subset of file system types 144 * b) if the partition (in this state) has already been 145 * used before 146 * It is OK to leave all these zeroed / NULL when setting 147 * partition data - or leave them at the last values a get operation 148 * returned. Backends can not rely on them to be valid. 149 */ 150 const char *last_mounted; /* last mount point or NULL */ 151 unsigned int fs_type, fs_sub_type, /* FS_* type of filesystem 152 * and for some FS a sub 153 * type (e.g. FFSv1 vs. FFSv2) 154 */ 155 fs_opt1, fs_opt2, fs_opt3; /* FS specific option, used 156 * for FFS block/fragsize 157 * and inodes 158 */ 159 }; 160 161 /* An unused area that may be used for new partitions */ 162 struct disk_part_free_space { 163 daddr_t start, size; 164 }; 165 166 /* 167 * Some partition schemes define additional data that needs to be edited. 168 * These attributes are described in this structure and referenced by 169 * their index into the fixed list of available attributes. 170 */ 171 enum custom_attr_type { pet_bool, pet_cardinal, pet_str }; 172 struct disk_part_custom_attribute { 173 msg label; /* Name, like "active partition" */ 174 enum custom_attr_type type; /* bool, long, char* */ 175 size_t strlen; /* maximum length if pet_str */ 176 }; 177 178 /* 179 * When displaying a partition editor, we have standard columns, but 180 * partitioning schemes add custom columns to the table as well. 181 * There is a fixed number of columns and they are described by this 182 * structure: 183 */ 184 struct disk_part_edit_column_desc { 185 msg title; 186 unsigned int width; 187 }; 188 189 struct disk_partitions; /* in-memory representation of a set of partitions */ 190 191 /* 192 * When querying partition "device" names, we may ask for: 193 */ 194 enum dev_name_usage { 195 parent_device_only, /* wd0 instead of wd0i, no path */ 196 logical_name, /* NAME=my-root instead of dk7 */ 197 plain_name, /* e.g. /dev/wd0i or /dev/dk7 */ 198 raw_dev_name, /* e.g. /dev/rwd0i or /dev/rdk7 */ 199 }; 200 201 /* 202 * A scheme how to store partitions on-disk, and methods to read/write 203 * them to/from our abstract internal presentation. 204 */ 205 struct disk_partitioning_scheme { 206 /* name of the on-disk scheme, retrieved via msg_string */ 207 msg name, short_name; 208 209 /* prompt shown when creating custom partition types */ 210 msg new_type_prompt; 211 212 /* description of scheme specific partition flags */ 213 msg part_flag_desc; 214 215 /* 216 * size restrictions for this partitioning scheme (number 217 * of 512 byte sectors max) 218 */ 219 daddr_t size_limit; /* 0 if not limited */ 220 221 /* 222 * If this scheme allows sub-partitions (i.e. MBR -> disklabel), 223 * this is a pointer to the (potential/optional) secondary 224 * scheme. Depending on partitioning details it may not be 225 * used in the end. 226 * This link is only here for better help messages. 227 * See *secondary_partitions further below for actually accessing 228 * secondary partitions. 229 */ 230 const struct disk_partitioning_scheme *secondary_scheme; 231 232 /* 233 * Partition editor colum descriptions for whatever the scheme 234 * needs to display (see format_partition_table_str below). 235 */ 236 size_t edit_columns_count; 237 const struct disk_part_edit_column_desc *edit_columns; 238 239 /* 240 * Custom attributes editable by the partitioning scheme (but of 241 * no particular meaning for sysinst) 242 */ 243 size_t custom_attribute_count; 244 const struct disk_part_custom_attribute *custom_attributes; 245 246 /* 247 * Partition types supported by this scheme, 248 * first function gets the number, second queries single elements 249 */ 250 size_t (*get_part_types_count)(void); 251 const struct part_type_desc * (*get_part_type)(size_t ndx); 252 /* 253 * Get the preferred native representation for a generic partition type 254 */ 255 const struct part_type_desc * (*get_generic_part_type)(enum part_type); 256 /* 257 * Get the preferred native partition type for a specific file system 258 * type (FS_*) and subtype (fs specific value) 259 */ 260 const struct part_type_desc * (*get_fs_part_type)( 261 enum part_type, unsigned, unsigned); 262 /* 263 * Optional: inverse to above: given a part_type_desc, set default 264 * fstype and subtype. 265 */ 266 bool (*get_default_fstype)(const struct part_type_desc *, 267 unsigned *fstype, unsigned *fs_sub_type); 268 /* 269 * Create a custom partition type. If the type already exists 270 * (or there is a collision), the old existing type will be 271 * returned and no new type created. This is not considered 272 * an error (to keep the user interface simple). 273 * On failure NULL is returned and (if passed != NULL) 274 * *err_msg is set to a message describing the error. 275 */ 276 const struct part_type_desc * (*create_custom_part_type) 277 (const char *custom, const char **err_msg); 278 /* 279 * Return a usable internal partition type representation 280 * for types that are not otherwise mappable. 281 * This could be FS_OTHER for disklabel, or a randomly 282 * created type guid for GPT. This type may or may not be 283 * in the regular type list. If not, it needs to behave like a 284 * custom type. 285 */ 286 const struct part_type_desc * (*create_unknown_part_type)(void); 287 288 /* 289 * Global attributes 290 */ 291 /* 292 * Get partition alignment suggestion. The schemen may enforce 293 * additional/different alignment for some partitions. 294 */ 295 daddr_t (*get_part_alignment)(const struct disk_partitions*); 296 297 /* 298 * Methods to manipulate the in-memory abstract representation 299 */ 300 301 /* Retrieve data about a single partition, identified by the part_id. 302 * Fill the disk_part_info structure 303 */ 304 bool (*get_part_info)(const struct disk_partitions*, part_id, 305 struct disk_part_info*); 306 307 /* Optional: fill an attribute string describing the given partition */ 308 bool (*get_part_attr_str)(const struct disk_partitions*, part_id, 309 char *str, size_t avail_space); 310 /* Format a partition editor element for the "col" column in 311 * edit_columns. Used e.g. with MBR to set "active" flags. 312 */ 313 bool (*format_partition_table_str)(const struct disk_partitions*, 314 part_id, size_t col, char *outstr, size_t outspace); 315 316 /* is the type of this partition changeable? */ 317 bool (*part_type_can_change)(const struct disk_partitions*, 318 part_id); 319 320 /* can we add further partitions? */ 321 bool (*can_add_partition)(const struct disk_partitions*); 322 323 /* is the custom attribute changeable? */ 324 bool (*custom_attribute_writable)(const struct disk_partitions*, 325 part_id, size_t attr_no); 326 /* 327 * Output formatting for custom attributes. 328 * If "info" is != NULL, use (where it makes sense) 329 * values from that structure, as if a call to set_part_info 330 * would have been done before this call. 331 */ 332 bool (*format_custom_attribute)(const struct disk_partitions*, 333 part_id, size_t attr_no, const struct disk_part_info *info, 334 char *out, size_t out_space); 335 /* value setter functions for custom attributes */ 336 /* pet_bool: */ 337 bool (*custom_attribute_toggle)(struct disk_partitions*, 338 part_id, size_t attr_no); 339 /* pet_cardinal: */ 340 bool (*custom_attribute_set_card)(struct disk_partitions*, 341 part_id, size_t attr_no, long new_val); 342 /* pet_str or pet_cardinal: */ 343 bool (*custom_attribute_set_str)(struct disk_partitions*, 344 part_id, size_t attr_no, const char *new_val); 345 346 /* 347 * Optional: additional user information when showing the size 348 * editor (especially for existing unknown partitions) 349 */ 350 const char * (*other_partition_identifier)(const struct 351 disk_partitions*, part_id); 352 353 354 /* Retrieve device and partition names, e.g. for checking 355 * against kern.root_device or invoking newfs. 356 * For disklabel partitions, "part" will be set to the partition 357 * index (a = 0, b = 1, ...), for others it will get set to -1. 358 * If dev_name_usage is parent_device_only, the device name will 359 * not include a partition letter - obviously this only makes a 360 * difference with disklabel partitions. 361 * If dev_name_usage is logical_name instead of a device name 362 * a given name may be returned in NAME= syntax. 363 * If with_path is true (and the returned value is a device 364 * node), include the /dev/ prefix in the result string 365 * (this is ignored when returning NAME= syntax for /etc/fstab). 366 * If life is true, the device must be made available under 367 * that name (only makes a difference for NAME=syntax if 368 * no wedge has been created yet,) - implied for all variants 369 * where dev_name_usage != logical_name. 370 */ 371 bool (*get_part_device)(const struct disk_partitions*, 372 part_id, char *devname, size_t max_devname_len, int *part, 373 enum dev_name_usage, bool with_path, bool life); 374 375 /* 376 * How big could we resize the given position (start of existing 377 * partition or free space) 378 */ 379 daddr_t (*max_free_space_at)(const struct disk_partitions*, daddr_t); 380 381 /* 382 * Provide a list of free spaces usable for further partitioning, 383 * assuming the given partition alignment. 384 * If start is > 0 no space with lower sector numbers will 385 * be found. 386 * If ignore is > 0, any partition starting at that sector will 387 * be considered "free", this is used e.g. when moving an existing 388 * partition around. 389 */ 390 size_t (*get_free_spaces)(const struct disk_partitions*, 391 struct disk_part_free_space *result, size_t max_num_result, 392 daddr_t min_space_size, daddr_t align, daddr_t start, 393 daddr_t ignore /* -1 */); 394 395 /* 396 * Translate a partition description from a foreign partitioning 397 * scheme as close as possible to what we can handle in add_partition. 398 * This mostly adjusts flags and partition type pointers (using 399 * more lose matching than add_partition would do). 400 */ 401 bool (*adapt_foreign_part_info)( 402 const struct disk_partitions *myself, struct disk_part_info *dest, 403 const struct disk_partitioning_scheme *src_scheme, 404 const struct disk_part_info *src); 405 406 /* 407 * Update data for an existing partition 408 */ 409 bool (*set_part_info)(struct disk_partitions*, part_id, 410 const struct disk_part_info*, const char **err_msg); 411 412 /* Add a new partition and return its part_id. */ 413 part_id (*add_partition)(struct disk_partitions*, 414 const struct disk_part_info*, const char **err_msg); 415 416 /* 417 * Optional: add a partition from an outer scheme, accept all 418 * details w/o verification as best as possible. 419 */ 420 part_id (*add_outer_partition)(struct disk_partitions*, 421 const struct disk_part_info*, const char **err_msg); 422 423 /* Delete all partitions */ 424 bool (*delete_all_partitions)(struct disk_partitions*); 425 426 /* Optional: delete any partitions inside the given range */ 427 bool (*delete_partitions_in_range)(struct disk_partitions*, 428 daddr_t start, daddr_t size); 429 430 /* Delete the specified partition */ 431 bool (*delete_partition)(struct disk_partitions*, part_id, 432 const char **err_msg); 433 434 /* 435 * Methods for the whole set of partitions 436 */ 437 /* 438 * If this scheme only creates a singly NetBSD partition, which 439 * then is sub-partitioned (usually by disklabel), this returns a 440 * pointer to the secondary partition set. 441 * Otherwise NULL is returned, e.g. when there is no 442 * NetBSD partition defined (so this might change over time). 443 * Schemes that NEVER use a secondary scheme set this 444 * function pointer to NULL. 445 * 446 * If force_empty = true, ignore all on-disk contents and just 447 * create a new disk_partitions structure for the secondary scheme 448 * (this is used after deleting all partitions and setting up 449 * things for "use whole disk"). 450 * 451 * The returned pointer is always owned by the primary partitions, 452 * caller MUST never free it, but otherwise can manipulate it 453 * arbitrarily. 454 */ 455 struct disk_partitions * 456 (*secondary_partitions)(struct disk_partitions *, daddr_t start, 457 bool force_empty); 458 459 /* 460 * Write the whole set (in new_state) back to disk. 461 */ 462 bool (*write_to_disk)(struct disk_partitions *new_state); 463 464 /* 465 * Try to read partitions from a disk, return NULL if this is not 466 * the partitioning scheme in use on that device. 467 * Usually start and len are 0 (and ignored). 468 * If this is about a part of a disk (like only the NetBSD 469 * MBR partition, start and len are the valid part of the 470 * disk. 471 */ 472 struct disk_partitions * (*read_from_disk)(const char *, 473 daddr_t start, daddr_t len, size_t bytes_per_sec, 474 const struct disk_partitioning_scheme *); 475 476 /* 477 * Set up all internal data for a new disk. 478 */ 479 struct disk_partitions * (*create_new_for_disk)(const char *, 480 daddr_t start, daddr_t len, bool is_boot_drive, 481 struct disk_partitions *parent); 482 483 /* 484 * Optional: this scheme may be used to boot from the given disk 485 */ 486 bool (*have_boot_support)(const char *disk); 487 488 /* 489 * Optional: try to guess disk geometry from the partition information 490 */ 491 int (*guess_disk_geom)(struct disk_partitions *, 492 int *cyl, int *head, int *sec); 493 494 /* 495 * Return a "cylinder size" (in number of blocks) - whatever that 496 * means to a particular partitioning scheme. 497 */ 498 size_t (*get_cylinder_size)(const struct disk_partitions *); 499 500 /* 501 * Optional: change used geometry info and update internal state 502 */ 503 bool (*change_disk_geom)(struct disk_partitions *, 504 int cyl, int head, int sec); 505 506 /* 507 * Optional: 508 * Get or set a name for the whole disk (most partitioning 509 * schemes do not provide this). Used for disklabel "pack names", 510 * which then may be used for aut-discovery of wedges, so it 511 * makes sense for the user to edit them. 512 */ 513 bool (*get_disk_pack_name)(const struct disk_partitions *, 514 char *, size_t); 515 bool (*set_disk_pack_name)(struct disk_partitions *, const char *); 516 517 /* 518 * Optional: 519 * Find a partition by name (as used in /etc/fstab NAME= entries) 520 */ 521 part_id (*find_by_name)(struct disk_partitions *, const char *name); 522 523 /* 524 * Optional: 525 * Try to guess install target partition from internal data, 526 * returns true if a safe match was found and sets start/size 527 * to the target partition. 528 */ 529 bool (*guess_install_target)(const struct disk_partitions *, 530 daddr_t *start, daddr_t *size); 531 532 /* 533 * Optional: verify that the whole set of partitions would be bootable, 534 * fix up any issues (with user interaction) where needed. 535 * If "quiet" is true, fix up everything silently if possible 536 * and never return 1. 537 * Returns: 538 * 0: abort install 539 * 1: re-edit partitions 540 * 2: use anyway (continue) 541 */ 542 int (*post_edit_verify)(struct disk_partitions *, bool quiet); 543 544 /* 545 * Optional: called during updates, before mounting the target disk(s), 546 * before md_pre_update() is called. Can be used to fixup 547 * partition info for historic errors (e.g. i386 changing MBR 548 * partition type from 165 to 169), similar to post_edit_verify. 549 * Returns: 550 * true if the partition info has changed (write back required) 551 * false if nothing further needs to be done. 552 */ 553 bool (*pre_update_verify)(struct disk_partitions *); 554 555 /* Free all the data */ 556 void (*free)(struct disk_partitions*); 557 558 /* Wipe all on-disk state, leave blank disk - and free data */ 559 void (*destroy_part_scheme)(struct disk_partitions*); 560 561 /* Scheme global cleanup */ 562 void (*cleanup)(void); 563 }; 564 565 /* 566 * The in-memory representation of all partitions on a concrete disk, 567 * tied to the partitioning scheme in use. 568 * 569 * Concrete schemes will derive from the abstract disk_partitions 570 * structure (by aggregation), but consumers of the API will only 571 * ever see this public part. 572 */ 573 struct disk_partitions { 574 /* which partitioning scheme is in use */ 575 const struct disk_partitioning_scheme *pscheme; 576 577 /* the disk device this came from (or should go to) */ 578 const char *disk; 579 580 /* global/public disk data */ 581 582 /* 583 * The basic unit of size used for this disk (all "start", 584 * "size" and "align" values are in this unit). 585 */ 586 size_t bytes_per_sector; /* must be 2^n and >= 512 */ 587 588 /* 589 * Valid partitions may have IDs in the range 0 .. num_part (excl.) 590 */ 591 part_id num_part; 592 593 /* 594 * If this is a sub-partitioning, the start of the "disk" is 595 * some arbitrary partition in the parent. Sometimes we need 596 * to be able to calculate absoluted offsets. 597 */ 598 daddr_t disk_start; 599 /* 600 * Total size of the disk (usable for partitioning) 601 */ 602 daddr_t disk_size; 603 604 /* 605 * Space not yet allocated 606 */ 607 daddr_t free_space; 608 609 /* 610 * If this is the secondary partitioning scheme, pointer to 611 * the outer one. Otherwise NULL. 612 */ 613 struct disk_partitions *parent; 614 }; 615 616 /* 617 * A list of partitioning schemes, so we can iterate over everything 618 * supported (e.g. when partitioning a new disk). NULL terminated. 619 */ 620 extern const struct disk_partitioning_scheme **available_part_schemes; 621 extern size_t num_available_part_schemes; 622 623 /* 624 * Generic reader - query a disk device and read all partitions from it 625 */ 626 struct disk_partitions * 627 partitions_read_disk(const char *, daddr_t disk_size, 628 size_t bytes_per_sector, bool no_mbr); 629 630 /* 631 * Generic part info adaption, may be overridden by individual partitioning 632 * schemes 633 */ 634 bool generic_adapt_foreign_part_info( 635 const struct disk_partitions *myself, struct disk_part_info *dest, 636 const struct disk_partitioning_scheme *src_scheme, 637 const struct disk_part_info *src); 638 639 /* 640 * One time initialization and cleanup 641 */ 642 void partitions_init(void); 643 void partitions_cleanup(void); 644 645