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