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