Merge commit '2cedd8f0ecbd2b29bf0aac72bb8b7413b0326938' into merges
[unleashed.git] / usr / src / cmd / format / partition.c
blob80b4e964f0101dd8aa3f126cc7f6c6e418145729
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
28 * This file contains functions that operate on partition tables.
30 #include <string.h>
31 #include <stdlib.h>
32 #include "global.h"
33 #include "partition.h"
34 #include "misc.h"
35 #include "menu_command.h"
36 #include "menu_partition.h"
40 * Default vtoc information for non-SVr4 partitions
42 struct dk_map2 default_vtoc_map[NDKMAP] = {
43 { V_ROOT, 0 }, /* a - 0 */
44 { V_SWAP, V_UNMNT }, /* b - 1 */
45 { V_BACKUP, V_UNMNT }, /* c - 2 */
46 { V_UNASSIGNED, 0 }, /* d - 3 */
47 { V_UNASSIGNED, 0 }, /* e - 4 */
48 { V_UNASSIGNED, 0 }, /* f - 5 */
49 { V_USR, 0 }, /* g - 6 */
50 { V_UNASSIGNED, 0 }, /* h - 7 */
52 #if defined(_SUNOS_VTOC_16)
54 #if defined(i386)
55 { V_BOOT, V_UNMNT }, /* i - 8 */
56 { V_ALTSCTR, 0 }, /* j - 9 */
58 #else
59 #error No VTOC format defined.
60 #endif /* defined(i386) */
62 { V_UNASSIGNED, 0 }, /* k - 10 */
63 { V_UNASSIGNED, 0 }, /* l - 11 */
64 { V_UNASSIGNED, 0 }, /* m - 12 */
65 { V_UNASSIGNED, 0 }, /* n - 13 */
66 { V_UNASSIGNED, 0 }, /* o - 14 */
67 { V_UNASSIGNED, 0 }, /* p - 15 */
68 #endif /* defined(_SUNOS_VTOC_16) */
72 * This routine finds the last usable sector in the partition table.
73 * It skips the BACKUP partition.
75 static uint64_t
76 maxofN(struct dk_gpt *map)
78 uint64_t max;
79 uint64_t sec_no[2], start[2], size[2];
80 int i;
82 for (i = 0; i < map->efi_nparts - 1; i++) {
83 start[0] = map->efi_parts[i].p_start;
84 size[0] = map->efi_parts[i].p_size;
85 sec_no[0] = start[0] + size[0];
87 start[1] = map->efi_parts[i+1].p_start;
88 size[1] = map->efi_parts[i+1].p_size;
89 sec_no[1] = start[1] + size[1];
91 if (map->efi_parts[i].p_tag == V_BACKUP) {
92 sec_no[0] = 0;
94 if (map->efi_parts[i+1].p_tag == V_BACKUP) {
95 sec_no[1] = 0;
97 if (i == 0) {
98 max = sec_no[1];
100 if (sec_no[0] > max) {
101 max = sec_no[0];
102 } else {
103 max = max;
106 if (max == 0)
107 max = 34;
108 return (max);
112 * This routine allows the user to change the boundaries of the given
113 * partition in the current partition map.
115 void
116 change_partition(int num)
118 uint_t i;
119 uint64_t i64, j64;
120 uint_t j;
121 int deflt;
122 part_deflt_t p_deflt;
123 u_ioparam_t ioparam;
124 int tag;
125 int flag;
126 char msg[256];
127 blkaddr32_t cyl_offset = 0;
128 efi_deflt_t efi_deflt;
131 * check if there exists a partition table for the disk.
133 if (cur_parts == NULL) {
134 err_print("Current Disk has no partition table.\n");
135 return;
138 if (cur_label == L_TYPE_EFI) {
139 if (num > cur_parts->etoc->efi_nparts - 1) {
140 err_print("Invalid partition for EFI label\n");
141 return;
143 print_efi_partition(cur_parts->etoc, num, 1);
144 fmt_print("\n");
146 * Prompt for p_tag and p_flag values for this partition
148 deflt = cur_parts->etoc->efi_parts[num].p_tag;
149 if (deflt == V_UNASSIGNED) {
150 deflt = V_USR;
152 (void) sprintf(msg, "Enter partition id tag");
153 ioparam.io_slist = ptag_choices;
154 tag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT);
156 deflt = cur_parts->etoc->efi_parts[num].p_flag;
157 (void) sprintf(msg, "Enter partition permission flags");
158 ioparam.io_slist = pflag_choices;
159 flag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT);
161 ioparam.io_bounds.lower = 34;
162 ioparam.io_bounds.upper = cur_parts->etoc->efi_last_u_lba;
164 efi_deflt.start_sector = maxofN(cur_parts->etoc);
165 if ((cur_parts->etoc->efi_parts[num].p_start != 0) &&
166 (cur_parts->etoc->efi_parts[num].p_size != 0)) {
167 efi_deflt.start_sector =
168 cur_parts->etoc->efi_parts[num].p_start;
170 efi_deflt.end_sector = ioparam.io_bounds.upper -
171 efi_deflt.start_sector;
172 i64 = input(FIO_INT64, "Enter new starting Sector", ':', &ioparam,
173 (int *)&efi_deflt, DATA_INPUT);
175 ioparam.io_bounds.lower = 0;
176 ioparam.io_bounds.upper = cur_parts->etoc->efi_last_u_lba;
177 efi_deflt.end_sector = cur_parts->etoc->efi_parts[num].p_size;
178 efi_deflt.start_sector = i64;
179 j64 = input(FIO_EFI, "Enter partition size", ':', &ioparam,
180 (int *)&efi_deflt, DATA_INPUT);
181 if (j64 == 0) {
182 tag = V_UNASSIGNED;
183 i64 = 0;
184 } else if ((j64 != 0) && (tag == V_UNASSIGNED)) {
185 tag = V_USR;
188 if (cur_parts->pinfo_name != NULL)
189 make_partition();
191 cur_parts->etoc->efi_parts[num].p_tag = tag;
192 cur_parts->etoc->efi_parts[num].p_flag = flag;
193 cur_parts->etoc->efi_parts[num].p_start = i64;
194 cur_parts->etoc->efi_parts[num].p_size = j64;
196 * We are now done with EFI part, so return now
198 return;
201 * Print out the given partition so the user knows what they're
202 * getting into.
204 print_partition(cur_parts, num, 1);
205 fmt_print("\n");
208 * Prompt for p_tag and p_flag values for this partition.
210 assert(cur_parts->vtoc.v_version == V_VERSION);
211 deflt = cur_parts->vtoc.v_part[num].p_tag;
212 (void) sprintf(msg, "Enter partition id tag");
213 ioparam.io_slist = ptag_choices;
214 tag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT);
216 deflt = cur_parts->vtoc.v_part[num].p_flag;
217 (void) sprintf(msg, "Enter partition permission flags");
218 ioparam.io_slist = pflag_choices;
219 flag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT);
222 * Ask for the new values. The old values are the defaults, and
223 * strict bounds checking is done on the values given.
226 #if defined(i386)
228 if (tag != V_UNASSIGNED && tag != V_BACKUP && tag != V_BOOT) {
230 * Determine cyl offset for boot and alternate partitions.
231 * Assuming that the alternate sectors partition (slice)
232 * physical location immediately follows the boot
233 * partition and partition sizes are expressed in multiples
234 * of cylinder size.
236 cyl_offset = cur_parts->pinfo_map[I_PARTITION].dkl_cylno + 1;
237 if (tag != V_ALTSCTR) {
238 if (cur_parts->pinfo_map[J_PARTITION].dkl_nblk != 0) {
239 cyl_offset =
240 cur_parts->pinfo_map[J_PARTITION].dkl_cylno +
241 ((cur_parts->pinfo_map[J_PARTITION].dkl_nblk +
242 (spc()-1)) / spc());
246 #endif /* defined(i386) */
248 ioparam.io_bounds.lower = 0;
249 ioparam.io_bounds.upper = ncyl - 1;
250 deflt = max(cur_parts->pinfo_map[num].dkl_cylno,
251 cyl_offset);
252 i = (uint_t)input(FIO_INT, "Enter new starting cyl", ':', &ioparam,
253 &deflt, DATA_INPUT);
255 ioparam.io_bounds.lower = 0;
256 ioparam.io_bounds.upper = (ncyl - i) * spc();
258 /* fill in defaults for the current partition */
259 p_deflt.start_cyl = i;
260 p_deflt.deflt_size =
261 min(cur_parts->pinfo_map[num].dkl_nblk,
262 ioparam.io_bounds.upper);
264 /* call input, passing p_deflt's address, typecast to (int *) */
265 j = (uint_t)input(FIO_ECYL, "Enter partition size", ':', &ioparam,
266 (int *)&p_deflt, DATA_INPUT);
269 * If the current partition has a size of zero change the
270 * tag to Unassigned and the starting cylinder to zero
273 if (j == 0) {
274 tag = V_UNASSIGNED;
275 i = 0;
279 #if defined(i386)
281 if (i < cyl_offset && tag != V_UNASSIGNED && tag != V_BACKUP &&
282 tag != V_BOOT) {
284 * This slice overlaps boot and/or alternates slice
285 * Check if it's the boot or alternates slice and warn
286 * accordingly
288 if (i < cur_parts->pinfo_map[I_PARTITION].dkl_cylno + 1) {
289 fmt_print("\nWarning: Partition overlaps boot ");
290 fmt_print("partition. Specify different start cyl.\n");
291 return;
294 * Cyl offset for alternates partition was calculated before
296 if (i < cyl_offset) {
297 fmt_print("\nWarning: Partition overlaps alternates ");
298 fmt_print("partition. Specify different start cyl.\n");
299 return;
303 #endif /* defined(i386) */
306 * If user has entered a V_BACKUP tag then the partition
307 * size should specify full disk capacity else
308 * return an Error.
310 if (tag == V_BACKUP) {
311 uint_t fullsz;
313 fullsz = ncyl * nhead * nsect;
314 if (fullsz != j) {
316 * V_BACKUP Tag Partition != full disk capacity.
317 * print useful messages.
319 fmt_print("\nWarning: Partition with V_BACKUP tag should ");
320 fmt_print("specify full disk capacity. \n");
321 return;
327 * If the current partition is named, we can't change it.
328 * We create a new current partition map instead.
330 if (cur_parts->pinfo_name != NULL)
331 make_partition();
333 * Change the values.
335 cur_parts->pinfo_map[num].dkl_cylno = i;
336 cur_parts->pinfo_map[num].dkl_nblk = j;
338 #if defined(_SUNOS_VTOC_16)
339 cur_parts->vtoc.v_part[num].p_start = (daddr_t)(i * (nhead * nsect));
340 cur_parts->vtoc.v_part[num].p_size = (long)j;
341 #endif /* defined(_SUNOS_VTOC_16) */
344 * Install the p_tag and p_flag values for this partition
346 assert(cur_parts->vtoc.v_version == V_VERSION);
347 cur_parts->vtoc.v_part[num].p_tag = (ushort_t)tag;
348 cur_parts->vtoc.v_part[num].p_flag = (ushort_t)flag;
353 * This routine picks to closest partition table which matches the
354 * selected disk type. It is called each time the disk type is
355 * changed. If no match is found, it uses the first element
356 * of the partition table. If no table exists, a dummy is
357 * created.
360 get_partition()
362 register struct partition_info *pptr;
363 register struct partition_info *parts;
366 * If there are no pre-defined maps for this disk type, it's
367 * an error.
369 parts = cur_dtype->dtype_plist;
370 if (parts == NULL) {
371 err_print("No defined partition tables.\n");
372 make_partition();
373 return (-1);
376 * Loop through the pre-defined maps searching for one which match
377 * disk type. If found copy it into unmamed partition.
379 enter_critical();
380 for (pptr = parts; pptr != NULL; pptr = pptr->pinfo_next) {
381 if (cur_dtype->dtype_asciilabel) {
382 if (pptr->pinfo_name != NULL && strcmp(pptr->pinfo_name,
383 cur_dtype->dtype_asciilabel) == 0) {
385 * Set current partition and name it.
387 cur_disk->disk_parts = cur_parts = pptr;
388 cur_parts->pinfo_name = pptr->pinfo_name;
389 exit_critical();
390 return (0);
395 * If we couldn't find a match, take the first one.
396 * Set current partition and name it.
398 cur_disk->disk_parts = cur_parts = cur_dtype->dtype_plist;
399 cur_parts->pinfo_name = parts->pinfo_name;
400 exit_critical();
401 return (0);
406 * This routine creates a new partition map and sets it current. If there
407 * was a current map, the new map starts out identical to it. Otherwise
408 * the new map starts out all zeroes.
410 void
411 make_partition()
413 register struct partition_info *pptr, *parts;
414 int i;
417 * Lock out interrupts so the lists don't get mangled.
419 enter_critical();
421 * Get space for for the new map and link it into the list
422 * of maps for the current disk type.
424 pptr = (struct partition_info *)zalloc(sizeof (struct partition_info));
425 parts = cur_dtype->dtype_plist;
426 if (parts == NULL) {
427 cur_dtype->dtype_plist = pptr;
428 } else {
429 while (parts->pinfo_next != NULL) {
430 parts = parts->pinfo_next;
432 parts->pinfo_next = pptr;
433 pptr->pinfo_next = NULL;
436 * If there was a current map, copy its values.
438 if (cur_label == L_TYPE_EFI) {
439 struct dk_gpt *map;
440 int nparts;
441 int size;
443 nparts = cur_parts->etoc->efi_nparts;
444 size = sizeof (struct dk_part) * nparts + sizeof (struct dk_gpt);
445 map = zalloc(size);
446 (void) memcpy(map, cur_parts->etoc, size);
447 pptr->etoc = map;
448 cur_disk->disk_parts = cur_parts = pptr;
449 exit_critical();
450 return;
452 if (cur_parts != NULL) {
453 for (i = 0; i < NDKMAP; i++) {
454 pptr->pinfo_map[i] = cur_parts->pinfo_map[i];
456 pptr->vtoc = cur_parts->vtoc;
457 } else {
459 * Otherwise set initial default vtoc values
461 set_vtoc_defaults(pptr);
465 * Make the new one current.
467 cur_disk->disk_parts = cur_parts = pptr;
468 exit_critical();
473 * This routine deletes a partition map from the list of maps for
474 * the given disk type.
476 void
477 delete_partition(struct partition_info *parts)
479 struct partition_info *pptr;
482 * If there isn't a current map, it's an error.
484 if (cur_dtype->dtype_plist == NULL) {
485 err_print("Error: unexpected null partition list.\n");
486 fullabort();
489 * Remove the map from the list.
491 if (cur_dtype->dtype_plist == parts)
492 cur_dtype->dtype_plist = parts->pinfo_next;
493 else {
494 for (pptr = cur_dtype->dtype_plist; pptr->pinfo_next != parts;
495 pptr = pptr->pinfo_next)
497 pptr->pinfo_next = parts->pinfo_next;
500 * Free the space it was using.
502 destroy_data((char *)parts);
507 * Set all partition vtoc fields to defaults
509 void
510 set_vtoc_defaults(struct partition_info *part)
512 int i;
514 bzero((caddr_t)&part->vtoc, sizeof (struct dk_vtoc));
516 part->vtoc.v_version = V_VERSION;
517 part->vtoc.v_nparts = NDKMAP;
518 part->vtoc.v_sanity = VTOC_SANE;
520 for (i = 0; i < NDKMAP; i++) {
521 part->vtoc.v_part[i].p_tag = default_vtoc_map[i].p_tag;
522 part->vtoc.v_part[i].p_flag = default_vtoc_map[i].p_flag;