Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / cmd / format / modify_partition.c
blob02fee8c67b92808c3a690449d88db33cb82ff8d9
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.
27 * This file contains functions to implement the partition menu commands.
29 #include <stdlib.h>
30 #include <string.h>
31 #include "global.h"
32 #include "partition.h"
33 #include "menu_partition.h"
34 #include "menu_command.h"
35 #include "modify_partition.h"
36 #include "checkdev.h"
37 #include "misc.h"
38 #include "label.h"
39 #include "auto_sense.h"
41 #ifdef __STDC__
43 /* Function prototypes for ANSI C Compilers */
45 static void adj_cyl_offset(struct dk_map32 *map);
46 static int check_map(struct dk_map32 *map);
47 static void get_user_map(struct dk_map32 *map, int float_part);
48 static void get_user_map_efi(struct dk_gpt *map, int float_part);
50 #else /* __STDC__ */
52 /* Function prototypes for non-ANSI C Compilers */
54 static void adj_cyl_offset();
55 static int check_map();
56 static void get_user_map();
57 static void get_user_map_efi();
59 #endif /* __STDC__ */
61 static char *partn_list[] = { "0", "1", "2", "3", "4", "5", "6", "7", NULL };
63 static char *sel_list[] = { "0", "1", "2", "3", NULL };
65 #define MBYTE (1024*1024)
69 * Modify/Create a predefined partition table.
71 int
72 p_modify()
74 struct partition_info tmp_pinfo[1];
75 struct dk_map32 *map = tmp_pinfo->pinfo_map;
76 u_ioparam_t ioparam;
77 int inpt_dflt = 0;
78 int free_hog = -1;
79 int i;
80 char tmpstr[80];
81 char tmpstr2[300];
82 int sel_type = 0;
85 * There must be a current disk type (and therefore a current disk).
87 if (cur_dtype == NULL) {
88 err_print("Current Disk Type is not set.\n");
89 return (-1);
93 * check if there exists a partition table for the disk.
95 if (cur_parts == NULL) {
96 err_print("Current Disk has no partition table.\n");
97 return (-1);
102 * If the disk has mounted partitions, cannot modify
104 if (checkmount((diskaddr_t)-1, (diskaddr_t)-1)) {
105 err_print(
106 "Cannot modify disk partitions while it has mounted partitions.\n\n");
107 return (-1);
111 * If the disk has partitions currently being used for
112 * swapping, cannot modify
114 if (checkswap((diskaddr_t)-1, (diskaddr_t)-1)) {
115 err_print(
116 "Cannot modify disk partitions while it is \
117 currently being used for swapping.\n");
118 return (-1);
122 * Check to see if any partitions used for svm, vxvm, ZFS zpool
123 * or live upgrade are on the disk.
125 if (checkdevinuse(cur_disk->disk_name, (diskaddr_t)-1,
126 (diskaddr_t)-1, 0, 0)) {
127 err_print("Cannot modify disk partition when "
128 "partitions are in use as described.\n");
129 return (-1);
133 * prompt user for a partition table base
135 if (cur_parts->pinfo_name != NULL) {
136 (void) snprintf(tmpstr, sizeof (tmpstr),
137 "\t0. Current partition table (%s)",
138 cur_parts->pinfo_name);
139 } else {
140 (void) sprintf(tmpstr,
141 "\t0. Current partition table (unnamed)");
144 (void) snprintf(tmpstr2, sizeof (tmpstr2),
145 "Select partitioning base:\n%s\n"
146 "\t1. All Free Hog\n"
147 "Choose base (enter number) ",
148 tmpstr);
150 ioparam.io_charlist = sel_list;
151 sel_type = input(FIO_MSTR, tmpstr2, '?', &ioparam,
152 &sel_type, DATA_INPUT);
154 switch (cur_label) {
155 case L_TYPE_SOLARIS:
156 if (sel_type == 0) {
158 * Check for invalid parameters but do
159 * not modify the table.
161 if (check_map(cur_parts->pinfo_map)) {
162 err_print("\
163 Warning: Fix, or select a different partition table.\n");
164 return (0);
167 * Create partition map from existing map
169 tmp_pinfo->vtoc = cur_parts->vtoc;
170 for (i = 0; i < NDKMAP; i++) {
171 map[i].dkl_nblk = cur_parts->pinfo_map[i].dkl_nblk;
172 map[i].dkl_cylno = cur_parts->pinfo_map[i].dkl_cylno;
174 } else {
176 * Make an empty partition map, with all the space
177 * in the c partition.
179 set_vtoc_defaults(tmp_pinfo);
180 for (i = 0; i < NDKMAP; i++) {
181 map[i].dkl_nblk = 0;
182 map[i].dkl_cylno = 0;
184 map[C_PARTITION].dkl_nblk = ncyl * spc();
186 #if defined(i386)
188 * Adjust for the boot and possibly alternates partitions
190 map[I_PARTITION].dkl_nblk = spc();
191 map[I_PARTITION].dkl_cylno = 0;
192 if (cur_ctype->ctype_ctype != DKC_SCSI_CCS) {
193 map[J_PARTITION].dkl_nblk = 2 * spc();
194 map[J_PARTITION].dkl_cylno = spc() / spc();
196 #endif /* defined(i386) */
198 break;
199 case L_TYPE_EFI:
200 if (sel_type == 1) {
201 for (i = 0; i < cur_parts->etoc->efi_nparts; i++) {
202 cur_parts->etoc->efi_parts[i].p_start = 0;
203 cur_parts->etoc->efi_parts[i].p_size = 0;
206 break;
209 fmt_print("\n");
210 if (cur_label == L_TYPE_SOLARIS) {
211 print_map(tmp_pinfo);
212 } else {
213 print_map(cur_parts);
216 ioparam.io_charlist = confirm_list;
217 if (input(FIO_MSTR,
218 "Do you wish to continue creating a new partition\ntable based on above table",
219 '?', &ioparam, &inpt_dflt, DATA_INPUT)) {
220 return (0);
224 * get Free Hog partition
226 inpt_dflt = 1;
227 while ((free_hog < 0) && (cur_label == L_TYPE_SOLARIS)) {
228 free_hog = G_PARTITION; /* default to g partition */
229 ioparam.io_charlist = partn_list;
230 free_hog = input(FIO_MSTR, "Free Hog partition", '?',
231 &ioparam, &free_hog, DATA_INPUT);
232 /* disallow c partition */
233 if (free_hog == C_PARTITION) {
234 fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
235 C_PARTITION + PARTITION_BASE);
236 free_hog = -1;
237 continue;
240 * If user selected all float set the
241 * float to be the whole disk.
243 if (sel_type == 1) {
244 map[free_hog].dkl_nblk = map[C_PARTITION].dkl_nblk;
245 #if defined(i386)
246 map[free_hog].dkl_nblk -= map[I_PARTITION].dkl_nblk;
247 if (cur_ctype->ctype_ctype != DKC_SCSI_CCS) {
248 map[free_hog].dkl_nblk -=
249 map[J_PARTITION].dkl_nblk;
251 #endif /* defined(i386) */
252 break;
255 * Warn the user if there is no free space in
256 * the float partition.
258 if (map[free_hog].dkl_nblk == 0) {
259 err_print("\
260 Warning: No space available from Free Hog partition.\n");
261 ioparam.io_charlist = confirm_list;
262 if (input(FIO_MSTR, "Continue", '?',
263 &ioparam, &inpt_dflt, DATA_INPUT)) {
264 free_hog = -1;
268 inpt_dflt = 0;
270 if (cur_label == L_TYPE_EFI) {
271 free_hog = G_PARTITION; /* default to g partition */
272 ioparam.io_charlist = partn_list;
273 free_hog = input(FIO_MSTR, "Free Hog partition", '?',
274 &ioparam, &free_hog, DATA_INPUT);
275 /* disallow c partition */
276 if (free_hog == C_PARTITION) {
277 fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
278 C_PARTITION + PARTITION_BASE);
279 return (-1);
281 get_user_map_efi(cur_parts->etoc, free_hog);
282 print_map(cur_parts);
283 if (check("Ready to label disk, continue")) {
284 return (-1);
286 fmt_print("\n");
287 if (write_label()) {
288 err_print("Writing label failed\n");
289 return (-1);
291 return (0);
294 * get user modified partition table
296 get_user_map(map, free_hog);
299 * Update cylno offsets
301 adj_cyl_offset(map);
303 fmt_print("\n");
304 print_map(tmp_pinfo);
306 ioparam.io_charlist = confirm_list;
307 if (input(FIO_MSTR, "\
308 Okay to make this the current partition table", '?',
309 &ioparam, &inpt_dflt, DATA_INPUT)) {
310 return (0);
311 } else {
312 make_partition();
314 * Update new partition map
316 for (i = 0; i < NDKMAP; i++) {
317 cur_parts->pinfo_map[i].dkl_nblk = map[i].dkl_nblk;
318 cur_parts->pinfo_map[i].dkl_cylno = map[i].dkl_cylno;
319 #ifdef i386
320 cur_parts->vtoc.v_part[i].p_start =
321 map[i].dkl_cylno * nhead * nsect;
322 cur_parts->vtoc.v_part[i].p_size =
323 map[i].dkl_nblk;
324 #endif
326 (void) p_name();
329 * Label the disk now
331 if (check("Ready to label disk, continue")) {
332 return (-1);
334 fmt_print("\n");
335 if (write_label()) {
336 err_print("Writing label failed\n");
337 return (-1);
339 return (0);
346 * Adjust cylinder offsets
348 static void
349 adj_cyl_offset(map)
350 struct dk_map32 *map;
352 int i;
353 int cyloffset = 0;
357 * Update cylno offsets
360 #if defined(_SUNOS_VTOC_16)
362 * Correct cylinder allocation for having the boot and alternates
363 * slice in the beginning of the disk
365 for (i = NDKMAP/2; i < NDKMAP; i++) {
366 if (i != C_PARTITION && map[i].dkl_nblk) {
367 map[i].dkl_cylno = cyloffset;
368 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
369 } else if (map[i].dkl_nblk == 0) {
370 map[i].dkl_cylno = 0;
373 for (i = 0; i < NDKMAP/2; i++) {
375 #else /* !defined(_SUNOS_VTOC_16) */
376 for (i = 0; i < NDKMAP; i++) {
377 #endif /* defined(_SUNOS_VTOC_16) */
379 if (i != C_PARTITION && map[i].dkl_nblk) {
380 map[i].dkl_cylno = cyloffset;
381 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
382 } else if (map[i].dkl_nblk == 0) {
383 map[i].dkl_cylno = 0;
390 * Check partition table
392 static int
393 check_map(map)
394 struct dk_map32 *map;
396 int i;
397 int cyloffset = 0;
398 blkaddr32_t tot_blks = 0;
400 #ifdef i386
402 * On x86, we must account for the boot and alternates
404 cyloffset = map[0].dkl_cylno;
405 tot_blks = map[0].dkl_nblk;
406 #endif
409 * Do some checks for invalid parameters but do
410 * not modify the table.
412 for (i = 0; i < NDKMAP; i++) {
413 if (map[i].dkl_cylno > (blkaddr32_t)ncyl-1) {
414 err_print("\
415 Warning: Partition %c starting cylinder %d is out of range.\n",
416 (PARTITION_BASE+i), map[i].dkl_cylno);
417 return (-1);
419 if (map[i].dkl_nblk >
420 (blkaddr32_t)(ncyl - map[i].dkl_cylno) * spc()) {
421 err_print("\
422 Warning: Partition %c, specified # of blocks, %u, is out of range.\n",
423 (PARTITION_BASE+i), map[i].dkl_nblk);
424 return (-1);
426 if (i != C_PARTITION && map[i].dkl_nblk) {
427 #ifdef i386
428 if (i == I_PARTITION || i == J_PARTITION)
429 continue;
430 #endif
431 if (map[i].dkl_cylno < cyloffset) {
432 err_print(
433 "Warning: Overlapping partition (%c) in table.\n", PARTITION_BASE+i);
434 return (-1);
435 } else if (map[i].dkl_cylno > cyloffset) {
436 err_print(
437 "Warning: Non-contiguous partition (%c) in table.\n", PARTITION_BASE+i);
439 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
440 tot_blks = map[i].dkl_nblk;
443 if (tot_blks > map[C_PARTITION].dkl_nblk) {
444 err_print("\
445 Warning: Total blocks used is greater than number of blocks in '%c'\n\
446 \tpartition.\n", C_PARTITION + PARTITION_BASE);
447 return (-1);
449 return (0);
455 * get user defined partitions
457 static void
458 get_user_map(map, float_part)
459 struct dk_map32 *map;
460 int float_part;
462 int i;
463 blkaddr32_t newsize;
464 blkaddr32_t deflt;
465 char tmpstr[80];
466 u_ioparam_t ioparam;
469 * Get partition sizes
471 for (i = 0; i < NDKMAP; i++) {
472 if (partn_list[i] == NULL)
473 break;
474 if ((i == C_PARTITION) || (i == float_part))
475 continue;
476 else {
477 ioparam.io_bounds.lower = 0;
478 ioparam.io_bounds.upper = map[i].dkl_nblk +
479 map[float_part].dkl_nblk;
480 deflt = map[i].dkl_nblk;
481 if (ioparam.io_bounds.upper == 0) {
482 err_print("\
483 Warning: no space available for '%s' from Free Hog partition\n",
484 partn_list[i]);
485 continue;
487 (void) snprintf(tmpstr, sizeof (tmpstr),
488 "Enter size of partition '%s' ",
489 partn_list[i]);
490 newsize = (blkaddr32_t)input(FIO_CYL, tmpstr, ':',
491 &ioparam, (int *)&deflt, DATA_INPUT);
492 map[float_part].dkl_nblk -= (newsize - map[i].dkl_nblk);
493 map[i].dkl_nblk = newsize;
498 static struct partition_info *
499 build_partition(tptr)
500 struct disk_type *tptr;
502 struct partition_info *part;
503 struct dk_label *label;
504 int i;
506 #ifdef DEBUG
507 fmt_print("Creating Default Partition for the disk \n");
508 #endif
510 * construct a label and pass it on to
511 * build_default_partition() which builds the
512 * default partition list.
514 label = zalloc(sizeof (struct dk_label));
515 label->dkl_pcyl = tptr->dtype_pcyl;
516 label->dkl_ncyl = tptr->dtype_ncyl;
517 label->dkl_acyl = tptr->dtype_acyl;
518 label->dkl_nhead = tptr->dtype_nhead;
519 label->dkl_nsect = tptr->dtype_nsect;
520 label->dkl_apc = apc;
521 label->dkl_intrlv = 1;
522 label->dkl_rpm = tptr->dtype_rpm;
524 if (!build_default_partition(label, cur_ctype->ctype_ctype))
525 return (NULL);
527 part = (struct partition_info *)
528 zalloc(sizeof (struct partition_info));
529 part->pinfo_name = alloc_string(tptr->dtype_asciilabel);
531 * Fill in the partition info from the label
533 for (i = 0; i < NDKMAP; i++) {
534 #if defined(_SUNOS_VTOC_8)
535 part->pinfo_map[i] = label->dkl_map[i];
536 #else
537 part->pinfo_map[i].dkl_cylno =
538 label->dkl_vtoc.v_part[i].p_start /
539 (blkaddr32_t)(tptr->dtype_nhead * tptr->dtype_nsect - apc);
540 part->pinfo_map[i].dkl_nblk =
541 label->dkl_vtoc.v_part[i].p_size;
542 #endif /* ifdefined(_SUNOS_VTOC_8) */
544 part->vtoc = label->dkl_vtoc;
545 return (part);
549 * build new partition table for given disk type
551 static void
552 get_user_map_efi(map, float_part)
553 struct dk_gpt *map;
554 int float_part;
557 int i;
558 efi_deflt_t efi_deflt;
559 u_ioparam_t ioparam;
560 char tmpstr[80];
561 uint64_t i64;
562 uint64_t start_lba = 34;
564 for (i = 0; i < map->efi_nparts - 1; i++) {
565 if (i == float_part)
566 continue;
567 else {
568 ioparam.io_bounds.lower = start_lba;
569 ioparam.io_bounds.upper = map->efi_last_u_lba;
570 efi_deflt.start_sector = ioparam.io_bounds.lower;
571 efi_deflt.end_sector = map->efi_parts[i].p_size;
572 (void) sprintf(tmpstr,
573 "Enter size of partition %d ", i);
574 i64 = input(FIO_EFI, tmpstr, ':',
575 &ioparam, (int *)&efi_deflt, DATA_INPUT);
576 if (i64 == 0) {
577 map->efi_parts[i].p_tag = V_UNASSIGNED;
578 } else if ((i64 != 0) && (map->efi_parts[i].p_tag ==
579 V_UNASSIGNED)) {
580 map->efi_parts[i].p_tag = V_USR;
582 if (i64 == 0) {
583 map->efi_parts[i].p_start = 0;
584 } else {
585 map->efi_parts[i].p_start = start_lba;
587 map->efi_parts[i].p_size = i64;
588 start_lba += i64;
591 map->efi_parts[float_part].p_start = start_lba;
592 map->efi_parts[float_part].p_size = map->efi_last_u_lba -
593 start_lba - (1024 * 16);
594 map->efi_parts[float_part].p_tag = V_USR;
595 if (map->efi_parts[float_part].p_size == UINT_MAX64) {
596 map->efi_parts[float_part].p_size = 0;
597 map->efi_parts[float_part].p_start = 0;
598 map->efi_parts[float_part].p_tag = V_UNASSIGNED;
599 fmt_print("Warning: No space left for HOG\n");
602 for (i = 0; i < map->efi_nparts; i++) {
603 if (map->efi_parts[i].p_tag == V_RESERVED) {
604 map->efi_parts[i].p_start = map->efi_last_u_lba -
605 (1024 * 16);
606 map->efi_parts[i].p_size = (1024 * 16);
607 break;
613 void
614 new_partitiontable(tptr, oldtptr)
615 struct disk_type *tptr, *oldtptr;
617 struct partition_info *part;
620 * check if disk geometry has changed , if so add new
621 * partition table else copy the old partition table.(best guess).
623 if ((oldtptr != NULL) &&
624 (tptr->dtype_ncyl == oldtptr->dtype_ncyl) &&
625 (tptr->dtype_nhead == oldtptr->dtype_nhead) &&
626 (tptr->dtype_nsect == oldtptr->dtype_nsect)) {
628 part = (struct partition_info *)
629 zalloc(sizeof (struct partition_info));
630 bcopy((char *)cur_parts, (char *)part,
631 sizeof (struct partition_info));
632 part->pinfo_next = tptr->dtype_plist;
633 tptr->dtype_plist = part;
634 } else {
636 #ifdef DEBUG
637 if (cur_parts != NULL) {
638 fmt_print("Warning: Partition Table is set");
639 fmt_print("to default partition table. \n");
641 #endif
642 if (tptr->dtype_plist == NULL) {
643 part = (struct partition_info *)build_partition(tptr);
644 if (part != NULL) {
645 part->pinfo_next = tptr->dtype_plist;
646 tptr->dtype_plist = part;