#include <stdlib.h>
#include <string.h>
#include "global.h"
#include "partition.h"
#include "menu_partition.h"
#include "menu_command.h"
#include "modify_partition.h"
#include "checkdev.h"
#include "misc.h"
#include "label.h"
#include "auto_sense.h"
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);
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)
int
p_modify(void)
{
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;
if (cur_dtype == NULL) {
err_print("Current Disk Type is not set.\n");
return (-1);
}
if (cur_parts == NULL) {
err_print("Current Disk has no partition table.\n");
return (-1);
}
if (checkmount((diskaddr_t)-1, (diskaddr_t)-1)) {
err_print(
"Cannot modify disk partitions while it has mounted partitions.\n\n");
return (-1);
}
if (checkswap((diskaddr_t)-1, (diskaddr_t)-1)) {
err_print(
"Cannot modify disk partitions while it is \
currently being used for swapping.\n");
return (-1);
}
if (checkdevinuse(cur_disk->disk_name, (diskaddr_t)-1,
(diskaddr_t)-1, 0, 0)) {
err_print("Cannot modify disk partition when "
"partitions are in use as described.\n");
return (-1);
}
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) {
if (check_map(cur_parts->pinfo_map)) {
err_print("Warning: Fix, or select a "
"different partition table.\n");
return (0);
}
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 {
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)
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
}
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);
}
inpt_dflt = 1;
while ((free_hog < 0) && (cur_label == L_TYPE_SOLARIS)) {
free_hog = G_PARTITION;
ioparam.io_charlist = partn_list;
free_hog = input(FIO_MSTR, "Free Hog partition", '?',
&ioparam, &free_hog, DATA_INPUT);
if (free_hog == C_PARTITION) {
fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
C_PARTITION + PARTITION_BASE);
free_hog = -1;
continue;
}
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
break;
}
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;
ioparam.io_charlist = partn_list;
free_hog = input(FIO_MSTR, "Free Hog partition", '?',
&ioparam, &free_hog, DATA_INPUT);
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_map(map, free_hog);
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();
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();
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);
}
}
static void
adj_cyl_offset(struct dk_map32 *map)
{
int i;
int cyloffset = 0;
#if defined(_SUNOS_VTOC_16)
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
for (i = 0; i < NDKMAP; i++) {
#endif
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;
}
}
}
static int
check_map(struct dk_map32 *map)
{
int i;
int cyloffset = 0;
blkaddr32_t tot_blks = 0;
#ifdef i386
cyloffset = map[0].dkl_cylno;
tot_blks = map[0].dkl_nblk;
#endif
for (i = 0; i < NDKMAP; i++) {
if (map[i].dkl_cylno > (blkaddr32_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 >
(blkaddr32_t)(ncyl - map[i].dkl_cylno) * spc()) {
err_print("Warning: Partition %c, specified # of "
"blocks, %u, 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);
}
static void
get_user_map(struct dk_map32 *map, int float_part)
{
int i;
blkaddr32_t newsize;
blkaddr32_t deflt;
char tmpstr[80];
u_ioparam_t ioparam;
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 = (blkaddr32_t)input(FIO_CYL, tmpstr, ':',
&ioparam, (int *)&deflt, DATA_INPUT);
map[float_part].dkl_nblk -= (newsize - map[i].dkl_nblk);
map[i].dkl_nblk = newsize;
}
}
}
static struct partition_info *
build_partition(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
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 = zalloc(sizeof (struct partition_info));
part->pinfo_name = alloc_string(tptr->dtype_asciilabel);
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 /
(blkaddr32_t)(tptr->dtype_nhead * tptr->dtype_nsect - apc);
part->pinfo_map[i].dkl_nblk =
label->dkl_vtoc.v_part[i].p_size;
#endif
}
part->vtoc = label->dkl_vtoc;
return (part);
}
static void
get_user_map_efi(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 = map->efi_first_u_lba;
uint64_t reserved;
reserved = efi_reserved_sectors(map);
for (i = 0; i < map->efi_nparts - 1; i++) {
if (i == float_part || i == 7)
continue;
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 + 1 -
start_lba - reserved;
map->efi_parts[float_part].p_tag = V_USR;
if (map->efi_parts[float_part].p_size == 0) {
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 -
reserved + 1;
map->efi_parts[i].p_size = reserved;
break;
}
}
}
void
new_partitiontable(struct disk_type *tptr, struct disk_type *oldtptr)
{
struct partition_info *part;
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;
}
}
}
}