6930152 6192139 (no reboot audit -- PSARC/2009/354) points out less than optimal...
[unleashed.git] / usr / src / cmd / format / modify_partition.c
blobb2bc580e69c5f68252fa95a6f4587868eb2e4d25
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
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This file contains functions to implement the partition menu commands.
29 #include "global.h"
30 #include "partition.h"
31 #include "menu_partition.h"
32 #include "menu_command.h"
33 #include "modify_partition.h"
34 #include "checkdev.h"
35 #include "misc.h"
36 #include "label.h"
37 #include "auto_sense.h"
39 #include <stdlib.h>
40 #include <string.h>
42 #ifdef __STDC__
44 /* Function prototypes for ANSI C Compilers */
46 static void adj_cyl_offset(struct dk_map32 *map);
47 static int check_map(struct dk_map32 *map);
48 static void get_user_map(struct dk_map32 *map, int float_part);
49 static void get_user_map_efi(struct dk_gpt *map, int float_part);
51 #else /* __STDC__ */
53 /* Function prototypes for non-ANSI C Compilers */
55 static void adj_cyl_offset();
56 static int check_map();
57 static void get_user_map();
58 static void get_user_map_efi();
60 #endif /* __STDC__ */
62 static char *partn_list[] = { "0", "1", "2", "3", "4", "5", "6", "7", NULL };
64 static char *sel_list[] = { "0", "1", "2", "3", NULL };
66 #define MBYTE (1024*1024)
70 * Modify/Create a predefined partition table.
72 int
73 p_modify()
75 struct partition_info tmp_pinfo[1];
76 struct dk_map32 *map = tmp_pinfo->pinfo_map;
77 u_ioparam_t ioparam;
78 int inpt_dflt = 0;
79 int free_hog = -1;
80 int i;
81 char tmpstr[80];
82 char tmpstr2[300];
83 int sel_type = 0;
86 * There must be a current disk type (and therefore a current disk).
88 if (cur_dtype == NULL) {
89 err_print("Current Disk Type is not set.\n");
90 return (-1);
94 * check if there exists a partition table for the disk.
96 if (cur_parts == NULL) {
97 err_print("Current Disk has no partition table.\n");
98 return (-1);
103 * If the disk has mounted partitions, cannot modify
105 if (checkmount((diskaddr_t)-1, (diskaddr_t)-1)) {
106 err_print(
107 "Cannot modify disk partitions while it has mounted partitions.\n\n");
108 return (-1);
112 * If the disk has partitions currently being used for
113 * swapping, cannot modify
115 if (checkswap((diskaddr_t)-1, (diskaddr_t)-1)) {
116 err_print(
117 "Cannot modify disk partitions while it is \
118 currently being used for swapping.\n");
119 return (-1);
123 * Check to see if any partitions used for svm, vxvm, ZFS zpool
124 * or live upgrade are on the disk.
126 if (checkdevinuse(cur_disk->disk_name, (diskaddr_t)-1,
127 (diskaddr_t)-1, 0, 0)) {
128 err_print("Cannot modify disk partition when "
129 "partitions are in use as described.\n");
130 return (-1);
134 * prompt user for a partition table base
136 if (cur_parts->pinfo_name != NULL) {
137 (void) snprintf(tmpstr, sizeof (tmpstr),
138 "\t0. Current partition table (%s)",
139 cur_parts->pinfo_name);
140 } else {
141 (void) sprintf(tmpstr,
142 "\t0. Current partition table (unnamed)");
145 (void) snprintf(tmpstr2, sizeof (tmpstr2),
146 "Select partitioning base:\n%s\n"
147 "\t1. All Free Hog\n"
148 "Choose base (enter number) ",
149 tmpstr);
151 ioparam.io_charlist = sel_list;
152 sel_type = input(FIO_MSTR, tmpstr2, '?', &ioparam,
153 &sel_type, DATA_INPUT);
155 switch (cur_label) {
156 case L_TYPE_SOLARIS:
157 if (sel_type == 0) {
159 * Check for invalid parameters but do
160 * not modify the table.
162 if (check_map(cur_parts->pinfo_map)) {
163 err_print("\
164 Warning: Fix, or select a different partition table.\n");
165 return (0);
168 * Create partition map from existing map
170 tmp_pinfo->vtoc = cur_parts->vtoc;
171 for (i = 0; i < NDKMAP; i++) {
172 map[i].dkl_nblk = cur_parts->pinfo_map[i].dkl_nblk;
173 map[i].dkl_cylno = cur_parts->pinfo_map[i].dkl_cylno;
175 } else {
177 * Make an empty partition map, with all the space
178 * in the c partition.
180 set_vtoc_defaults(tmp_pinfo);
181 for (i = 0; i < NDKMAP; i++) {
182 map[i].dkl_nblk = 0;
183 map[i].dkl_cylno = 0;
185 map[C_PARTITION].dkl_nblk = ncyl * spc();
187 #if defined(i386)
189 * Adjust for the boot and possibly alternates partitions
191 map[I_PARTITION].dkl_nblk = spc();
192 map[I_PARTITION].dkl_cylno = 0;
193 if (cur_ctype->ctype_ctype != DKC_SCSI_CCS) {
194 map[J_PARTITION].dkl_nblk = 2 * spc();
195 map[J_PARTITION].dkl_cylno = spc() / spc();
197 #endif /* defined(i386) */
199 break;
200 case L_TYPE_EFI:
201 if (sel_type == 1) {
202 for (i = 0; i < cur_parts->etoc->efi_nparts; i++) {
203 cur_parts->etoc->efi_parts[i].p_start = 0;
204 cur_parts->etoc->efi_parts[i].p_size = 0;
207 break;
210 fmt_print("\n");
211 if (cur_label == L_TYPE_SOLARIS) {
212 print_map(tmp_pinfo);
213 } else {
214 print_map(cur_parts);
217 ioparam.io_charlist = confirm_list;
218 if (input(FIO_MSTR,
219 "Do you wish to continue creating a new partition\ntable based on above table",
220 '?', &ioparam, &inpt_dflt, DATA_INPUT)) {
221 return (0);
225 * get Free Hog partition
227 inpt_dflt = 1;
228 while ((free_hog < 0) && (cur_label == L_TYPE_SOLARIS)) {
229 free_hog = G_PARTITION; /* default to g partition */
230 ioparam.io_charlist = partn_list;
231 free_hog = input(FIO_MSTR, "Free Hog partition", '?',
232 &ioparam, &free_hog, DATA_INPUT);
233 /* disallow c partition */
234 if (free_hog == C_PARTITION) {
235 fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
236 C_PARTITION + PARTITION_BASE);
237 free_hog = -1;
238 continue;
241 * If user selected all float set the
242 * float to be the whole disk.
244 if (sel_type == 1) {
245 map[free_hog].dkl_nblk = map[C_PARTITION].dkl_nblk;
246 #if defined(i386)
247 map[free_hog].dkl_nblk -= map[I_PARTITION].dkl_nblk;
248 if (cur_ctype->ctype_ctype != DKC_SCSI_CCS) {
249 map[free_hog].dkl_nblk -=
250 map[J_PARTITION].dkl_nblk;
252 #endif /* defined(i386) */
253 break;
256 * Warn the user if there is no free space in
257 * the float partition.
259 if (map[free_hog].dkl_nblk == 0) {
260 err_print("\
261 Warning: No space available from Free Hog partition.\n");
262 ioparam.io_charlist = confirm_list;
263 if (input(FIO_MSTR, "Continue", '?',
264 &ioparam, &inpt_dflt, DATA_INPUT)) {
265 free_hog = -1;
269 inpt_dflt = 0;
271 if (cur_label == L_TYPE_EFI) {
272 free_hog = G_PARTITION; /* default to g partition */
273 ioparam.io_charlist = partn_list;
274 free_hog = input(FIO_MSTR, "Free Hog partition", '?',
275 &ioparam, &free_hog, DATA_INPUT);
276 /* disallow c partition */
277 if (free_hog == C_PARTITION) {
278 fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
279 C_PARTITION + PARTITION_BASE);
280 return (-1);
282 get_user_map_efi(cur_parts->etoc, free_hog);
283 print_map(cur_parts);
284 if (check("Ready to label disk, continue")) {
285 return (-1);
287 fmt_print("\n");
288 if (write_label()) {
289 err_print("Writing label failed\n");
290 return (-1);
292 return (0);
295 * get user modified partition table
297 get_user_map(map, free_hog);
300 * Update cylno offsets
302 adj_cyl_offset(map);
304 fmt_print("\n");
305 print_map(tmp_pinfo);
307 ioparam.io_charlist = confirm_list;
308 if (input(FIO_MSTR, "\
309 Okay to make this the current partition table", '?',
310 &ioparam, &inpt_dflt, DATA_INPUT)) {
311 return (0);
312 } else {
313 make_partition();
315 * Update new partition map
317 for (i = 0; i < NDKMAP; i++) {
318 cur_parts->pinfo_map[i].dkl_nblk = map[i].dkl_nblk;
319 cur_parts->pinfo_map[i].dkl_cylno = map[i].dkl_cylno;
320 #ifdef i386
321 cur_parts->vtoc.v_part[i].p_start =
322 map[i].dkl_cylno * nhead * nsect;
323 cur_parts->vtoc.v_part[i].p_size =
324 map[i].dkl_nblk;
325 #endif
327 (void) p_name();
330 * Label the disk now
332 if (check("Ready to label disk, continue")) {
333 return (-1);
335 fmt_print("\n");
336 if (write_label()) {
337 err_print("Writing label failed\n");
338 return (-1);
340 return (0);
347 * Adjust cylinder offsets
349 static void
350 adj_cyl_offset(map)
351 struct dk_map32 *map;
353 int i;
354 int cyloffset = 0;
358 * Update cylno offsets
361 #if defined(_SUNOS_VTOC_16)
363 * Correct cylinder allocation for having the boot and alternates
364 * slice in the beginning of the disk
366 for (i = NDKMAP/2; i < NDKMAP; i++) {
367 if (i != C_PARTITION && map[i].dkl_nblk) {
368 map[i].dkl_cylno = cyloffset;
369 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
370 } else if (map[i].dkl_nblk == 0) {
371 map[i].dkl_cylno = 0;
374 for (i = 0; i < NDKMAP/2; i++) {
376 #else /* !defined(_SUNOS_VTOC_16) */
377 for (i = 0; i < NDKMAP; i++) {
378 #endif /* defined(_SUNOS_VTOC_16) */
380 if (i != C_PARTITION && map[i].dkl_nblk) {
381 map[i].dkl_cylno = cyloffset;
382 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
383 } else if (map[i].dkl_nblk == 0) {
384 map[i].dkl_cylno = 0;
391 * Check partition table
393 static int
394 check_map(map)
395 struct dk_map32 *map;
397 int i;
398 int cyloffset = 0;
399 blkaddr32_t tot_blks = 0;
401 #ifdef i386
403 * On x86, we must account for the boot and alternates
405 cyloffset = map[0].dkl_cylno;
406 tot_blks = map[0].dkl_nblk;
407 #endif
410 * Do some checks for invalid parameters but do
411 * not modify the table.
413 for (i = 0; i < NDKMAP; i++) {
414 if (map[i].dkl_cylno > (blkaddr32_t)ncyl-1) {
415 err_print("\
416 Warning: Partition %c starting cylinder %d is out of range.\n",
417 (PARTITION_BASE+i), map[i].dkl_cylno);
418 return (-1);
420 if (map[i].dkl_nblk >
421 (blkaddr32_t)(ncyl - map[i].dkl_cylno) * spc()) {
422 err_print("\
423 Warning: Partition %c, specified # of blocks, %u, is out of range.\n",
424 (PARTITION_BASE+i), map[i].dkl_nblk);
425 return (-1);
427 if (i != C_PARTITION && map[i].dkl_nblk) {
428 #ifdef i386
429 if (i == I_PARTITION || i == J_PARTITION)
430 continue;
431 #endif
432 if (map[i].dkl_cylno < cyloffset) {
433 err_print(
434 "Warning: Overlapping partition (%c) in table.\n", PARTITION_BASE+i);
435 return (-1);
436 } else if (map[i].dkl_cylno > cyloffset) {
437 err_print(
438 "Warning: Non-contiguous partition (%c) in table.\n", PARTITION_BASE+i);
440 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
441 tot_blks = map[i].dkl_nblk;
444 if (tot_blks > map[C_PARTITION].dkl_nblk) {
445 err_print("\
446 Warning: Total blocks used is greater than number of blocks in '%c'\n\
447 \tpartition.\n", C_PARTITION + PARTITION_BASE);
448 return (-1);
450 return (0);
456 * get user defined partitions
458 static void
459 get_user_map(map, float_part)
460 struct dk_map32 *map;
461 int float_part;
463 int i;
464 blkaddr32_t newsize;
465 blkaddr32_t deflt;
466 char tmpstr[80];
467 u_ioparam_t ioparam;
470 * Get partition sizes
472 for (i = 0; i < NDKMAP; i++) {
473 if (partn_list[i] == NULL)
474 break;
475 if ((i == C_PARTITION) || (i == float_part))
476 continue;
477 else {
478 ioparam.io_bounds.lower = 0;
479 ioparam.io_bounds.upper = map[i].dkl_nblk +
480 map[float_part].dkl_nblk;
481 deflt = map[i].dkl_nblk;
482 if (ioparam.io_bounds.upper == 0) {
483 err_print("\
484 Warning: no space available for '%s' from Free Hog partition\n",
485 partn_list[i]);
486 continue;
488 (void) snprintf(tmpstr, sizeof (tmpstr),
489 "Enter size of partition '%s' ",
490 partn_list[i]);
491 newsize = (blkaddr32_t)input(FIO_CYL, tmpstr, ':',
492 &ioparam, (int *)&deflt, DATA_INPUT);
493 map[float_part].dkl_nblk -= (newsize - map[i].dkl_nblk);
494 map[i].dkl_nblk = newsize;
499 static struct partition_info *
500 build_partition(tptr)
501 struct disk_type *tptr;
503 struct partition_info *part;
504 struct dk_label *label;
505 int i;
507 #ifdef DEBUG
508 fmt_print("Creating Default Partition for the disk \n");
509 #endif
511 * construct a label and pass it on to
512 * build_default_partition() which builds the
513 * default partition list.
515 label = zalloc(sizeof (struct dk_label));
516 label->dkl_pcyl = tptr->dtype_pcyl;
517 label->dkl_ncyl = tptr->dtype_ncyl;
518 label->dkl_acyl = tptr->dtype_acyl;
519 label->dkl_nhead = tptr->dtype_nhead;
520 label->dkl_nsect = tptr->dtype_nsect;
521 label->dkl_apc = apc;
522 label->dkl_intrlv = 1;
523 label->dkl_rpm = tptr->dtype_rpm;
525 if (!build_default_partition(label, cur_ctype->ctype_ctype))
526 return (NULL);
528 part = (struct partition_info *)
529 zalloc(sizeof (struct partition_info));
530 part->pinfo_name = alloc_string(tptr->dtype_asciilabel);
532 * Fill in the partition info from the label
534 for (i = 0; i < NDKMAP; i++) {
535 #if defined(_SUNOS_VTOC_8)
536 part->pinfo_map[i] = label->dkl_map[i];
537 #else
538 part->pinfo_map[i].dkl_cylno =
539 label->dkl_vtoc.v_part[i].p_start /
540 (blkaddr32_t)(tptr->dtype_nhead * tptr->dtype_nsect - apc);
541 part->pinfo_map[i].dkl_nblk =
542 label->dkl_vtoc.v_part[i].p_size;
543 #endif /* ifdefined(_SUNOS_VTOC_8) */
545 part->vtoc = label->dkl_vtoc;
546 return (part);
550 * build new partition table for given disk type
552 static void
553 get_user_map_efi(map, float_part)
554 struct dk_gpt *map;
555 int float_part;
558 int i;
559 efi_deflt_t efi_deflt;
560 u_ioparam_t ioparam;
561 char tmpstr[80];
562 uint64_t i64;
563 uint64_t start_lba = 34;
565 for (i = 0; i < map->efi_nparts - 1; i++) {
566 if (i == float_part)
567 continue;
568 else {
569 ioparam.io_bounds.lower = start_lba;
570 ioparam.io_bounds.upper = map->efi_last_u_lba;
571 efi_deflt.start_sector = ioparam.io_bounds.lower;
572 efi_deflt.end_sector = map->efi_parts[i].p_size;
573 (void) sprintf(tmpstr,
574 "Enter size of partition %d ", i);
575 i64 = input(FIO_EFI, tmpstr, ':',
576 &ioparam, (int *)&efi_deflt, DATA_INPUT);
577 if (i64 == 0) {
578 map->efi_parts[i].p_tag = V_UNASSIGNED;
579 } else if ((i64 != 0) && (map->efi_parts[i].p_tag ==
580 V_UNASSIGNED)) {
581 map->efi_parts[i].p_tag = V_USR;
583 if (i64 == 0) {
584 map->efi_parts[i].p_start = 0;
585 } else {
586 map->efi_parts[i].p_start = start_lba;
588 map->efi_parts[i].p_size = i64;
589 start_lba += i64;
592 map->efi_parts[float_part].p_start = start_lba;
593 map->efi_parts[float_part].p_size = map->efi_last_u_lba -
594 start_lba - (1024 * 16);
595 map->efi_parts[float_part].p_tag = V_USR;
596 if (map->efi_parts[float_part].p_size == UINT_MAX64) {
597 map->efi_parts[float_part].p_size = 0;
598 map->efi_parts[float_part].p_start = 0;
599 map->efi_parts[float_part].p_tag = V_UNASSIGNED;
600 fmt_print("Warning: No space left for HOG\n");
603 for (i = 0; i < map->efi_nparts; i++) {
604 if (map->efi_parts[i].p_tag == V_RESERVED) {
605 map->efi_parts[i].p_start = map->efi_last_u_lba -
606 (1024 * 16);
607 map->efi_parts[i].p_size = (1024 * 16);
608 break;
614 void
615 new_partitiontable(tptr, oldtptr)
616 struct disk_type *tptr, *oldtptr;
618 struct partition_info *part;
621 * check if disk geometry has changed , if so add new
622 * partition table else copy the old partition table.(best guess).
624 if ((oldtptr != NULL) &&
625 (tptr->dtype_ncyl == oldtptr->dtype_ncyl) &&
626 (tptr->dtype_nhead == oldtptr->dtype_nhead) &&
627 (tptr->dtype_nsect == oldtptr->dtype_nsect)) {
629 part = (struct partition_info *)
630 zalloc(sizeof (struct partition_info));
631 bcopy((char *)cur_parts, (char *)part,
632 sizeof (struct partition_info));
633 part->pinfo_next = tptr->dtype_plist;
634 tptr->dtype_plist = part;
635 } else {
637 #ifdef DEBUG
638 if (cur_parts != NULL) {
639 fmt_print("Warning: Partition Table is set");
640 fmt_print("to default partition table. \n");
642 #endif
643 if (tptr->dtype_plist == NULL) {
644 part = (struct partition_info *)build_partition(tptr);
645 if (part != NULL) {
646 part->pinfo_next = tptr->dtype_plist;
647 tptr->dtype_plist = part;