modify_partition.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file contains functions to implement the partition menu commands.
*/
#include "global.h"
#include "partition.h"
#include "menu_partition.h"
#include "menu_command.h"
#include "modify_partition.h"
#include "checkmount.h"
#include "misc.h"
#include "label.h"
#include "auto_sense.h"
#include <stdlib.h>
#include <string.h>
#ifdef __STDC__
/* Function prototypes for ANSI C Compilers */
static void adj_cyl_offset(struct dk_map32 *map);
static int check_map(struct dk_map32 *map);
static void get_user_map(struct dk_map32 *map, int float_part);
static void get_user_map_efi(struct dk_gpt *map, int float_part);
#else /* __STDC__ */
/* Function prototypes for non-ANSI C Compilers */
static void adj_cyl_offset();
static int check_map();
static void get_user_map();
static void get_user_map_efi();
#endif /* __STDC__ */
static char *partn_list[] = { "0", "1", "2", "3", "4", "5", "6", "7", NULL };
static char *sel_list[] = { "0", "1", "2", "3", NULL };
#define MBYTE (1024*1024)
/*
* Modify/Create a predefined partition table.
*/
int
p_modify()
{
struct partition_info tmp_pinfo[1];
struct dk_map32 *map = tmp_pinfo->pinfo_map;
u_ioparam_t ioparam;
int inpt_dflt = 0;
int free_hog = -1;
int i;
char tmpstr[80];
char tmpstr2[300];
int sel_type = 0;
/*
* There must be a current disk type (and therefore a current disk).
*/
if (cur_dtype == NULL) {
err_print("Current Disk Type is not set.\n");
return (-1);
}
/*
* check if there exists a partition table for the disk.
*/
if (cur_parts == NULL) {
err_print("Current Disk has no partition table.\n");
return (-1);
}
/*
* If the disk has mounted partitions, cannot modify
*/
if (checkmount((daddr_t)-1, (daddr_t)-1)) {
err_print(
"Cannot modify disk partitions while it has mounted partitions.\n\n");
return (-1);
}
/*
* If the disk has partitions currently being used for
* swapping, cannot modify
*/
if (checkswap((daddr_t)-1, (daddr_t)-1)) {
err_print(
"Cannot modify disk partitions while it is \
currently being used for swapping.\n");
return (-1);
}
/*
* prompt user for a partition table base
*/
if (cur_parts->pinfo_name != NULL) {
(void) snprintf(tmpstr, sizeof (tmpstr),
"\t0. Current partition table (%s)",
cur_parts->pinfo_name);
} else {
(void) sprintf(tmpstr,
"\t0. Current partition table (unnamed)");
}
(void) snprintf(tmpstr2, sizeof (tmpstr2),
"Select partitioning base:\n%s\n"
"\t1. All Free Hog\n"
"Choose base (enter number) ",
tmpstr);
ioparam.io_charlist = sel_list;
sel_type = input(FIO_MSTR, tmpstr2, '?', &ioparam,
&sel_type, DATA_INPUT);
switch (cur_label) {
case L_TYPE_SOLARIS:
if (sel_type == 0) {
/*
* Check for invalid parameters but do
* not modify the table.
*/
if (check_map(cur_parts->pinfo_map)) {
err_print("\
Warning: Fix, or select a different partition table.\n");
return (0);
}
/*
* Create partition map from existing map
*/
tmp_pinfo->vtoc = cur_parts->vtoc;
for (i = 0; i < NDKMAP; i++) {
map[i].dkl_nblk = cur_parts->pinfo_map[i].dkl_nblk;
map[i].dkl_cylno = cur_parts->pinfo_map[i].dkl_cylno;
}
} else {
/*
* Make an empty partition map, with all the space
* in the c partition.
*/
set_vtoc_defaults(tmp_pinfo);
for (i = 0; i < NDKMAP; i++) {
map[i].dkl_nblk = 0;
map[i].dkl_cylno = 0;
}
map[C_PARTITION].dkl_nblk = ncyl * spc();
#if defined(i386)
/*
* Adjust for the boot and possibly alternates partitions
*/
map[I_PARTITION].dkl_nblk = spc();
map[I_PARTITION].dkl_cylno = 0;
if (cur_ctype->ctype_ctype != DKC_SCSI_CCS) {
map[J_PARTITION].dkl_nblk = 2 * spc();
map[J_PARTITION].dkl_cylno = spc() / spc();
}
#endif /* defined(i386) */
}
break;
case L_TYPE_EFI:
if (sel_type == 1) {
for (i = 0; i < cur_parts->etoc->efi_nparts; i++) {
cur_parts->etoc->efi_parts[i].p_start = 0;
cur_parts->etoc->efi_parts[i].p_size = 0;
}
}
break;
}
fmt_print("\n");
if (cur_label == L_TYPE_SOLARIS) {
print_map(tmp_pinfo);
} else {
print_map(cur_parts);
}
ioparam.io_charlist = confirm_list;
if (input(FIO_MSTR,
"Do you wish to continue creating a new partition\ntable based on above table",
'?', &ioparam, &inpt_dflt, DATA_INPUT)) {
return (0);
}
/*
* get Free Hog partition
*/
inpt_dflt = 1;
while ((free_hog < 0) && (cur_label == L_TYPE_SOLARIS)) {
free_hog = G_PARTITION; /* default to g partition */
ioparam.io_charlist = partn_list;
free_hog = input(FIO_MSTR, "Free Hog partition", '?',
&ioparam, &free_hog, DATA_INPUT);
/* disallow c partition */
if (free_hog == C_PARTITION) {
fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
C_PARTITION + PARTITION_BASE);
free_hog = -1;
continue;
}
/*
* If user selected all float set the
* float to be the whole disk.
*/
if (sel_type == 1) {
map[free_hog].dkl_nblk = map[C_PARTITION].dkl_nblk;
#if defined(i386)
map[free_hog].dkl_nblk -= map[I_PARTITION].dkl_nblk;
if (cur_ctype->ctype_ctype != DKC_SCSI_CCS) {
map[free_hog].dkl_nblk -=
map[J_PARTITION].dkl_nblk;
}
#endif /* defined(i386) */
break;
}
/*
* Warn the user if there is no free space in
* the float partition.
*/
if (map[free_hog].dkl_nblk == 0) {
err_print("\
Warning: No space available from Free Hog partition.\n");
ioparam.io_charlist = confirm_list;
if (input(FIO_MSTR, "Continue", '?',
&ioparam, &inpt_dflt, DATA_INPUT)) {
free_hog = -1;
}
}
}
inpt_dflt = 0;
if (cur_label == L_TYPE_EFI) {
free_hog = G_PARTITION; /* default to g partition */
ioparam.io_charlist = partn_list;
free_hog = input(FIO_MSTR, "Free Hog partition", '?',
&ioparam, &free_hog, DATA_INPUT);
/* disallow c partition */
if (free_hog == C_PARTITION) {
fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
C_PARTITION + PARTITION_BASE);
return (-1);
}
get_user_map_efi(cur_parts->etoc, free_hog);
print_map(cur_parts);
if (check("Ready to label disk, continue")) {
return (-1);
}
fmt_print("\n");
if (write_label()) {
err_print("Writing label failed\n");
return (-1);
}
return (0);
}
/*
* get user modified partition table
*/
get_user_map(map, free_hog);
/*
* Update cylno offsets
*/
adj_cyl_offset(map);
fmt_print("\n");
print_map(tmp_pinfo);
ioparam.io_charlist = confirm_list;
if (input(FIO_MSTR, "\
Okay to make this the current partition table", '?',
&ioparam, &inpt_dflt, DATA_INPUT)) {
return (0);
} else {
make_partition();
/*
* Update new partition map
*/
for (i = 0; i < NDKMAP; i++) {
cur_parts->pinfo_map[i].dkl_nblk = map[i].dkl_nblk;
cur_parts->pinfo_map[i].dkl_cylno = map[i].dkl_cylno;
#ifdef i386
cur_parts->vtoc.v_part[i].p_start =
map[i].dkl_cylno * nhead * nsect;
cur_parts->vtoc.v_part[i].p_size =
map[i].dkl_nblk;
#endif
}
(void) p_name();
/*
* Label the disk now
*/
if (check("Ready to label disk, continue")) {
return (-1);
}
fmt_print("\n");
if (write_label()) {
err_print("Writing label failed\n");
return (-1);
}
return (0);
}
}
/*
* Adjust cylinder offsets
*/
static void
adj_cyl_offset(map)
struct dk_map32 *map;
{
int i;
int cyloffset = 0;
/*
* Update cylno offsets
*/
#if defined(_SUNOS_VTOC_16)
/*
* Correct cylinder allocation for having the boot and alternates
* slice in the beginning of the disk
*/
for (i = NDKMAP/2; i < NDKMAP; i++) {
if (i != C_PARTITION && map[i].dkl_nblk) {
map[i].dkl_cylno = cyloffset;
cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
} else if (map[i].dkl_nblk == 0) {
map[i].dkl_cylno = 0;
}
}
for (i = 0; i < NDKMAP/2; i++) {
#else /* !defined(_SUNOS_VTOC_16) */
for (i = 0; i < NDKMAP; i++) {
#endif /* defined(_SUNOS_VTOC_16) */
if (i != C_PARTITION && map[i].dkl_nblk) {
map[i].dkl_cylno = cyloffset;
cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
} else if (map[i].dkl_nblk == 0) {
map[i].dkl_cylno = 0;
}
}
}
/*
* Check partition table
*/
static int
check_map(map)
struct dk_map32 *map;
{
int i;
int cyloffset = 0;
int tot_blks = 0;
#ifdef i386
/*
* On x86, we must account for the boot and alternates
*/
cyloffset = map[0].dkl_cylno;
tot_blks = map[0].dkl_nblk;
#endif
/*
* Do some checks for invalid parameters but do
* not modify the table.
*/
for (i = 0; i < NDKMAP; i++) {
if (map[i].dkl_cylno < 0 ||
map[i].dkl_cylno > (daddr_t)ncyl-1) {
err_print("\
Warning: Partition %c starting cylinder %d is out of range.\n",
(PARTITION_BASE+i), map[i].dkl_cylno);
return (-1);
}
if (map[i].dkl_nblk < 0 || map[i].dkl_nblk > (daddr_t)(ncyl -
map[i].dkl_cylno) * spc()) {
err_print("\
Warning: Partition %c, specified # of blocks, %d, is out of range.\n",
(PARTITION_BASE+i), map[i].dkl_nblk);
return (-1);
}
if (i != C_PARTITION && map[i].dkl_nblk) {
#ifdef i386
if (i == I_PARTITION || i == J_PARTITION)
continue;
#endif
if (map[i].dkl_cylno < cyloffset) {
err_print(
"Warning: Overlapping partition (%c) in table.\n", PARTITION_BASE+i);
return (-1);
} else if (map[i].dkl_cylno > cyloffset) {
err_print(
"Warning: Non-contiguous partition (%c) in table.\n", PARTITION_BASE+i);
}
cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
tot_blks = map[i].dkl_nblk;
}
}
if (tot_blks > map[C_PARTITION].dkl_nblk) {
err_print("\
Warning: Total blocks used is greater than number of blocks in '%c'\n\
\tpartition.\n", C_PARTITION + PARTITION_BASE);
return (-1);
}
return (0);
}
/*
* get user defined partitions
*/
static void
get_user_map(map, float_part)
struct dk_map32 *map;
int float_part;
{
int i;
int newsize;
int deflt;
char tmpstr[80];
u_ioparam_t ioparam;
/*
* Get partition sizes
*/
for (i = 0; i < NDKMAP; i++) {
if (partn_list[i] == NULL)
break;
if ((i == C_PARTITION) || (i == float_part))
continue;
else {
ioparam.io_bounds.lower = 0;
ioparam.io_bounds.upper = map[i].dkl_nblk +
map[float_part].dkl_nblk;
deflt = map[i].dkl_nblk;
if (ioparam.io_bounds.upper == 0) {
err_print("\
Warning: no space available for '%s' from Free Hog partition\n",
partn_list[i]);
continue;
}
(void) snprintf(tmpstr, sizeof (tmpstr),
"Enter size of partition '%s' ",
partn_list[i]);
newsize = input(FIO_CYL, tmpstr, ':',
&ioparam, &deflt, DATA_INPUT);
map[float_part].dkl_nblk -= (newsize - map[i].dkl_nblk);
map[i].dkl_nblk = newsize;
}
}
}
static struct partition_info *
build_partition(tptr)
struct disk_type *tptr;
{
struct partition_info *part;
struct dk_label *label;
int i;
#ifdef DEBUG
fmt_print("Creating Default Partition for the disk \n");
#endif
/*
* construct a label and pass it on to
* build_default_partition() which builds the
* default partition list.
*/
label = zalloc(sizeof (struct dk_label));
label->dkl_pcyl = tptr->dtype_pcyl;
label->dkl_ncyl = tptr->dtype_ncyl;
label->dkl_acyl = tptr->dtype_acyl;
label->dkl_nhead = tptr->dtype_nhead;
label->dkl_nsect = tptr->dtype_nsect;
label->dkl_apc = apc;
label->dkl_intrlv = 1;
label->dkl_rpm = tptr->dtype_rpm;
if (!build_default_partition(label, cur_ctype->ctype_ctype))
return (NULL);
part = (struct partition_info *)
zalloc(sizeof (struct partition_info));
part->pinfo_name = alloc_string(tptr->dtype_asciilabel);
/*
* Fill in the partition info from the label
*/
for (i = 0; i < NDKMAP; i++) {
#if defined(_SUNOS_VTOC_8)
part->pinfo_map[i] = label->dkl_map[i];
#else
part->pinfo_map[i].dkl_cylno =
label->dkl_vtoc.v_part[i].p_start /
((int)(tptr->dtype_nhead * tptr->dtype_nsect - apc));
part->pinfo_map[i].dkl_nblk =
label->dkl_vtoc.v_part[i].p_size;
#endif /* ifdefined(_SUNOS_VTOC_8) */
}
part->vtoc = label->dkl_vtoc;
return (part);
}
/*
* build new partition table for given disk type
*/
static void
get_user_map_efi(map, float_part)
struct dk_gpt *map;
int float_part;
{
int i;
efi_deflt_t efi_deflt;
u_ioparam_t ioparam;
char tmpstr[80];
uint64_t i64;
uint64_t start_lba = 34;
for (i = 0; i < map->efi_nparts - 1; i++) {
if (i == float_part)
continue;
else {
ioparam.io_bounds.lower = start_lba;
ioparam.io_bounds.upper = map->efi_last_u_lba;
efi_deflt.start_sector = ioparam.io_bounds.lower;
efi_deflt.end_sector = map->efi_parts[i].p_size;
(void) sprintf(tmpstr,
"Enter size of partition %d ", i);
i64 = input(FIO_EFI, tmpstr, ':',
&ioparam, (int *)&efi_deflt, DATA_INPUT);
if (i64 == 0) {
map->efi_parts[i].p_tag = V_UNASSIGNED;
} else if ((i64 != 0) && (map->efi_parts[i].p_tag ==
V_UNASSIGNED)) {
map->efi_parts[i].p_tag = V_USR;
}
if (i64 == 0) {
map->efi_parts[i].p_start = 0;
} else {
map->efi_parts[i].p_start = start_lba;
}
map->efi_parts[i].p_size = i64;
start_lba += i64;
}
}
map->efi_parts[float_part].p_start = start_lba;
map->efi_parts[float_part].p_size = map->efi_last_u_lba -
start_lba - (1024 * 16);
map->efi_parts[float_part].p_tag = V_USR;
if (map->efi_parts[float_part].p_size == UINT_MAX64) {
map->efi_parts[float_part].p_size = 0;
map->efi_parts[float_part].p_start = 0;
map->efi_parts[float_part].p_tag = V_UNASSIGNED;
fmt_print("Warning: No space left for HOG\n");
}
for (i = 0; i < map->efi_nparts; i++) {
if (map->efi_parts[i].p_tag == V_RESERVED) {
map->efi_parts[i].p_start = map->efi_last_u_lba -
(1024 * 16);
map->efi_parts[i].p_size = (1024 * 16);
break;
}
}
}
void
new_partitiontable(tptr, oldtptr)
struct disk_type *tptr, *oldtptr;
{
struct partition_info *part;
/*
* check if disk geometry has changed , if so add new
* partition table else copy the old partition table.(best guess).
*/
if ((oldtptr != NULL) &&
(tptr->dtype_ncyl == oldtptr->dtype_ncyl) &&
(tptr->dtype_nhead == oldtptr->dtype_nhead) &&
(tptr->dtype_nsect == oldtptr->dtype_nsect)) {
part = (struct partition_info *)
zalloc(sizeof (struct partition_info));
bcopy((char *)cur_parts, (char *)part,
sizeof (struct partition_info));
part->pinfo_next = tptr->dtype_plist;
tptr->dtype_plist = part;
} else {
#ifdef DEBUG
if (cur_parts != NULL) {
fmt_print("Warning: Partition Table is set");
fmt_print("to default partition table. \n");
}
#endif
if (tptr->dtype_plist == NULL) {
part = (struct partition_info *)build_partition(tptr);
if (part != NULL) {
part->pinfo_next = tptr->dtype_plist;
tptr->dtype_plist = part;
}
}
}
}