Break libblkid into 4 libraries: libblkid, libuuid, libutil-linux and libfdisk. This should help in later patch updates. Change-Id: I680d9a7feb031e5c29a603e9c58aff4b65826262
1131 lines
30 KiB
C
1131 lines
30 KiB
C
/*
|
|
* Copyright (C) 2013 Karel Zak <kzak@redhat.com>
|
|
*
|
|
* Based on original code from fdisk:
|
|
* Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
|
|
* Merged with fdisk for other architectures, aeb, June 1998.
|
|
* Arnaldo Carvalho de Melo <acme@conectiva.com.br> Mar 1999, Internationalization
|
|
*/
|
|
#include <stdio.h> /* stderr */
|
|
#include <stdlib.h> /* qsort */
|
|
#include <string.h> /* strstr */
|
|
#include <unistd.h> /* write */
|
|
#include <sys/ioctl.h> /* ioctl */
|
|
|
|
#include "nls.h"
|
|
#include "blkdev.h"
|
|
#include "bitops.h"
|
|
|
|
#include "fdiskP.h"
|
|
#include "pt-sun.h"
|
|
#include "all-io.h"
|
|
|
|
|
|
/**
|
|
* SECTION: sun
|
|
* @title: SUN
|
|
* @short_description: disk label specific functions
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* in-memory fdisk SUN stuff
|
|
*/
|
|
struct fdisk_sun_label {
|
|
struct fdisk_label head; /* generic part */
|
|
struct sun_disklabel *header; /* on-disk data (pointer to cxt->firstsector) */
|
|
};
|
|
|
|
static struct fdisk_parttype sun_parttypes[] = {
|
|
{SUN_TAG_UNASSIGNED, N_("Unassigned")},
|
|
{SUN_TAG_BOOT, N_("Boot")},
|
|
{SUN_TAG_ROOT, N_("SunOS root")},
|
|
{SUN_TAG_SWAP, N_("SunOS swap")},
|
|
{SUN_TAG_USR, N_("SunOS usr")},
|
|
{SUN_TAG_WHOLEDISK, N_("Whole disk")},
|
|
{SUN_TAG_STAND, N_("SunOS stand")},
|
|
{SUN_TAG_VAR, N_("SunOS var")},
|
|
{SUN_TAG_HOME, N_("SunOS home")},
|
|
{SUN_TAG_ALTSCTR, N_("SunOS alt sectors")},
|
|
{SUN_TAG_CACHE, N_("SunOS cachefs")},
|
|
{SUN_TAG_RESERVED, N_("SunOS reserved")},
|
|
{SUN_TAG_LINUX_SWAP, N_("Linux swap")},
|
|
{SUN_TAG_LINUX_NATIVE, N_("Linux native")},
|
|
{SUN_TAG_LINUX_LVM, N_("Linux LVM")},
|
|
{SUN_TAG_LINUX_RAID, N_("Linux raid autodetect")},
|
|
{ 0, NULL }
|
|
};
|
|
|
|
/* return poiter buffer with on-disk data */
|
|
static inline struct sun_disklabel *self_disklabel(struct fdisk_context *cxt)
|
|
{
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
return ((struct fdisk_sun_label *) cxt->label)->header;
|
|
}
|
|
|
|
/* return in-memory sun fdisk data */
|
|
static inline struct fdisk_sun_label *self_label(struct fdisk_context *cxt)
|
|
{
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
return (struct fdisk_sun_label *) cxt->label;
|
|
}
|
|
|
|
static void set_partition(struct fdisk_context *cxt, size_t i,
|
|
uint32_t start,uint32_t stop, uint16_t sysid)
|
|
{
|
|
struct sun_disklabel *sunlabel = self_disklabel(cxt);
|
|
struct fdisk_parttype *t =
|
|
fdisk_label_get_parttype_from_code(cxt->label, sysid);
|
|
|
|
sunlabel->vtoc.infos[i].id = cpu_to_be16(sysid);
|
|
sunlabel->vtoc.infos[i].flags = cpu_to_be16(0);
|
|
sunlabel->partitions[i].start_cylinder =
|
|
cpu_to_be32(start / (cxt->geom.heads * cxt->geom.sectors));
|
|
sunlabel->partitions[i].num_sectors = cpu_to_be32(stop - start);
|
|
fdisk_label_set_changed(cxt->label, 1);
|
|
|
|
fdisk_info_new_partition(cxt, i + 1, start, stop, t);
|
|
}
|
|
|
|
static size_t count_used_partitions(struct fdisk_context *cxt)
|
|
{
|
|
struct sun_disklabel *sunlabel = self_disklabel(cxt);
|
|
size_t ct = 0, i;
|
|
|
|
assert(sunlabel);
|
|
|
|
for (i = 0; i < cxt->label->nparts_max; i++) {
|
|
if (sunlabel->partitions[i].num_sectors)
|
|
ct++;
|
|
}
|
|
return ct;
|
|
}
|
|
|
|
static int sun_probe_label(struct fdisk_context *cxt)
|
|
{
|
|
struct fdisk_sun_label *sun;
|
|
struct sun_disklabel *sunlabel;
|
|
unsigned short *ush;
|
|
int csum;
|
|
int need_fixing = 0;
|
|
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
/* map first sector to header */
|
|
sun = (struct fdisk_sun_label *) cxt->label;
|
|
sun->header = (struct sun_disklabel *) cxt->firstsector;
|
|
sunlabel = sun->header;
|
|
|
|
if (be16_to_cpu(sunlabel->magic) != SUN_LABEL_MAGIC) {
|
|
sun->header = NULL;
|
|
return 0; /* failed */
|
|
}
|
|
|
|
ush = ((unsigned short *) (sunlabel + 1)) - 1;
|
|
for (csum = 0; ush >= (unsigned short *)sunlabel;)
|
|
csum ^= *ush--;
|
|
|
|
if (csum) {
|
|
fdisk_warnx(cxt, _("Detected sun disklabel with wrong checksum. "
|
|
"Probably you'll have to set all the values, "
|
|
"e.g. heads, sectors, cylinders and partitions "
|
|
"or force a fresh label (s command in main menu)"));
|
|
return 1;
|
|
}
|
|
|
|
cxt->label->nparts_max = SUN_MAXPARTITIONS;
|
|
cxt->geom.heads = be16_to_cpu(sunlabel->nhead);
|
|
cxt->geom.cylinders = be16_to_cpu(sunlabel->ncyl);
|
|
cxt->geom.sectors = be16_to_cpu(sunlabel->nsect);
|
|
|
|
if (be32_to_cpu(sunlabel->vtoc.version) != SUN_VTOC_VERSION) {
|
|
fdisk_warnx(cxt, _("Detected sun disklabel with wrong version [%d]."),
|
|
be32_to_cpu(sunlabel->vtoc.version));
|
|
need_fixing = 1;
|
|
}
|
|
if (be32_to_cpu(sunlabel->vtoc.sanity) != SUN_VTOC_SANITY) {
|
|
fdisk_warnx(cxt, _("Detected sun disklabel with wrong vtoc.sanity [0x%08x]."),
|
|
be32_to_cpu(sunlabel->vtoc.sanity));
|
|
need_fixing = 1;
|
|
}
|
|
if (be16_to_cpu(sunlabel->vtoc.nparts) != SUN_MAXPARTITIONS) {
|
|
fdisk_warnx(cxt, _("Detected sun disklabel with wrong vtoc.nparts [%u]."),
|
|
be16_to_cpu(sunlabel->vtoc.nparts));
|
|
need_fixing = 1;
|
|
}
|
|
if (need_fixing) {
|
|
fdisk_warnx(cxt, _("Warning: Wrong values need to be fixed up and "
|
|
"will be corrected by w(rite)"));
|
|
|
|
sunlabel->vtoc.version = cpu_to_be32(SUN_VTOC_VERSION);
|
|
sunlabel->vtoc.sanity = cpu_to_be32(SUN_VTOC_SANITY);
|
|
sunlabel->vtoc.nparts = cpu_to_be16(SUN_MAXPARTITIONS);
|
|
|
|
ush = (unsigned short *)sunlabel;
|
|
csum = 0;
|
|
while(ush < (unsigned short *)(&sunlabel->csum))
|
|
csum ^= *ush++;
|
|
sunlabel->csum = csum;
|
|
|
|
fdisk_label_set_changed(cxt->label, 1);
|
|
}
|
|
|
|
cxt->label->nparts_cur = count_used_partitions(cxt);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void ask_geom(struct fdisk_context *cxt)
|
|
{
|
|
uintmax_t res;
|
|
|
|
assert(cxt);
|
|
|
|
if (fdisk_ask_number(cxt, 1, 1, 1024, _("Heads"), &res) == 0)
|
|
cxt->geom.heads = res;
|
|
if (fdisk_ask_number(cxt, 1, 1, 1024, _("Sectors/track"), &res) == 0)
|
|
cxt->geom.sectors = res;
|
|
if (fdisk_ask_number(cxt, 1, 1, USHRT_MAX, _("Cylinders"), &res) == 0)
|
|
cxt->geom.cylinders = res;
|
|
}
|
|
|
|
static int sun_create_disklabel(struct fdisk_context *cxt)
|
|
{
|
|
unsigned int ndiv;
|
|
struct fdisk_sun_label *sun; /* libfdisk sun handler */
|
|
struct sun_disklabel *sunlabel; /* on disk data */
|
|
int rc = 0;
|
|
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
/* map first sector to header */
|
|
rc = fdisk_init_firstsector_buffer(cxt);
|
|
if (rc)
|
|
return rc;
|
|
|
|
sun = (struct fdisk_sun_label *) cxt->label;
|
|
sun->header = (struct sun_disklabel *) cxt->firstsector;
|
|
|
|
sunlabel = sun->header;
|
|
|
|
cxt->label->nparts_max = SUN_MAXPARTITIONS;
|
|
|
|
sunlabel->magic = cpu_to_be16(SUN_LABEL_MAGIC);
|
|
sunlabel->vtoc.version = cpu_to_be32(SUN_VTOC_VERSION);
|
|
sunlabel->vtoc.sanity = cpu_to_be32(SUN_VTOC_SANITY);
|
|
sunlabel->vtoc.nparts = cpu_to_be16(SUN_MAXPARTITIONS);
|
|
|
|
#ifdef HDIO_GETGEO
|
|
if (cxt->geom.heads && cxt->geom.sectors) {
|
|
fdisk_sector_t llsectors;
|
|
|
|
if (blkdev_get_sectors(cxt->dev_fd, (unsigned long long *) &llsectors) == 0) {
|
|
int sec_fac = cxt->sector_size / 512;
|
|
fdisk_sector_t llcyls;
|
|
|
|
llcyls = llsectors / (cxt->geom.heads * cxt->geom.sectors * sec_fac);
|
|
cxt->geom.cylinders = llcyls;
|
|
if (cxt->geom.cylinders != llcyls)
|
|
cxt->geom.cylinders = ~0;
|
|
} else {
|
|
fdisk_warnx(cxt,
|
|
_("BLKGETSIZE ioctl failed on %s. "
|
|
"Using geometry cylinder value of %llu. "
|
|
"This value may be truncated for devices "
|
|
"> 33.8 GB."),
|
|
cxt->dev_path, cxt->geom.cylinders);
|
|
}
|
|
} else
|
|
#endif
|
|
ask_geom(cxt);
|
|
|
|
sunlabel->acyl = cpu_to_be16(0);
|
|
sunlabel->pcyl = cpu_to_be16(cxt->geom.cylinders);
|
|
sunlabel->rpm = cpu_to_be16(5400);
|
|
sunlabel->intrlv = cpu_to_be16(1);
|
|
sunlabel->apc = cpu_to_be16(0);
|
|
|
|
sunlabel->nhead = cpu_to_be16(cxt->geom.heads);
|
|
sunlabel->nsect = cpu_to_be16(cxt->geom.sectors);
|
|
sunlabel->ncyl = cpu_to_be16(cxt->geom.cylinders);
|
|
|
|
snprintf((char *) sunlabel->label_id, sizeof(sunlabel->label_id),
|
|
"Linux cyl %ju alt %u hd %u sec %ju",
|
|
(uintmax_t) cxt->geom.cylinders,
|
|
be16_to_cpu(sunlabel->acyl),
|
|
cxt->geom.heads,
|
|
(uintmax_t) cxt->geom.sectors);
|
|
|
|
if (cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors >= 150 * 2048) {
|
|
ndiv = cxt->geom.cylinders - (50 * 2048 / (cxt->geom.heads * cxt->geom.sectors)); /* 50M swap */
|
|
} else
|
|
ndiv = cxt->geom.cylinders * 2 / 3;
|
|
|
|
/* create the default layout only if no-script defined */
|
|
if (!cxt->script) {
|
|
set_partition(cxt, 0, 0, ndiv * cxt->geom.heads * cxt->geom.sectors,
|
|
SUN_TAG_LINUX_NATIVE);
|
|
set_partition(cxt, 1, ndiv * cxt->geom.heads * cxt->geom.sectors,
|
|
cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors,
|
|
SUN_TAG_LINUX_SWAP);
|
|
sunlabel->vtoc.infos[1].flags |= cpu_to_be16(SUN_FLAG_UNMNT);
|
|
|
|
set_partition(cxt, 2, 0,
|
|
cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors,
|
|
SUN_TAG_WHOLEDISK);
|
|
}
|
|
|
|
{
|
|
unsigned short *ush = (unsigned short *)sunlabel;
|
|
unsigned short csum = 0;
|
|
while(ush < (unsigned short *)(&sunlabel->csum))
|
|
csum ^= *ush++;
|
|
sunlabel->csum = csum;
|
|
}
|
|
|
|
fdisk_label_set_changed(cxt->label, 1);
|
|
cxt->label->nparts_cur = count_used_partitions(cxt);
|
|
|
|
fdisk_info(cxt, _("Created a new Sun disklabel."));
|
|
return 0;
|
|
}
|
|
|
|
static int sun_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsigned long flag)
|
|
{
|
|
struct sun_disklabel *sunlabel;
|
|
struct sun_info *p;
|
|
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
if (i >= cxt->label->nparts_max)
|
|
return -EINVAL;
|
|
|
|
sunlabel = self_disklabel(cxt);
|
|
p = &sunlabel->vtoc.infos[i];
|
|
|
|
switch (flag) {
|
|
case SUN_FLAG_UNMNT:
|
|
p->flags ^= cpu_to_be16(SUN_FLAG_UNMNT);
|
|
fdisk_label_set_changed(cxt->label, 1);
|
|
break;
|
|
case SUN_FLAG_RONLY:
|
|
p->flags ^= cpu_to_be16(SUN_FLAG_RONLY);
|
|
fdisk_label_set_changed(cxt->label, 1);
|
|
break;
|
|
default:
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void fetch_sun(struct fdisk_context *cxt,
|
|
uint32_t *starts,
|
|
uint32_t *lens,
|
|
uint32_t *start,
|
|
uint32_t *stop)
|
|
{
|
|
struct sun_disklabel *sunlabel;
|
|
int continuous = 1;
|
|
size_t i;
|
|
|
|
assert(cxt);
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
sunlabel = self_disklabel(cxt);
|
|
|
|
*start = 0;
|
|
*stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors;
|
|
|
|
for (i = 0; i < cxt->label->nparts_max; i++) {
|
|
struct sun_partition *part = &sunlabel->partitions[i];
|
|
struct sun_info *info = &sunlabel->vtoc.infos[i];
|
|
|
|
if (part->num_sectors &&
|
|
be16_to_cpu(info->id) != SUN_TAG_UNASSIGNED &&
|
|
be16_to_cpu(info->id) != SUN_TAG_WHOLEDISK) {
|
|
starts[i] = be32_to_cpu(part->start_cylinder) *
|
|
cxt->geom.heads * cxt->geom.sectors;
|
|
lens[i] = be32_to_cpu(part->num_sectors);
|
|
if (continuous) {
|
|
if (starts[i] == *start)
|
|
*start += lens[i];
|
|
else if (starts[i] + lens[i] >= *stop)
|
|
*stop = starts[i];
|
|
else
|
|
continuous = 0;
|
|
/* There will be probably more gaps
|
|
than one, so lets check afterwards */
|
|
}
|
|
} else {
|
|
starts[i] = 0;
|
|
lens[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_QSORT_R
|
|
static int verify_sun_cmp(int *a, int *b, void *data)
|
|
{
|
|
unsigned int *verify_sun_starts = (unsigned int *) data;
|
|
|
|
if (*a == -1)
|
|
return 1;
|
|
if (*b == -1)
|
|
return -1;
|
|
if (verify_sun_starts[*a] > verify_sun_starts[*b])
|
|
return 1;
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
static int sun_verify_disklabel(struct fdisk_context *cxt)
|
|
{
|
|
uint32_t starts[SUN_MAXPARTITIONS], lens[SUN_MAXPARTITIONS], start, stop;
|
|
uint32_t i,j,k,starto,endo;
|
|
#ifdef HAVE_QSORT_R
|
|
int array[SUN_MAXPARTITIONS];
|
|
unsigned int *verify_sun_starts;
|
|
#endif
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
fetch_sun(cxt, starts, lens, &start, &stop);
|
|
|
|
for (k = 0; k < 7; k++) {
|
|
for (i = 0; i < SUN_MAXPARTITIONS; i++) {
|
|
if (k && (lens[i] % (cxt->geom.heads * cxt->geom.sectors)))
|
|
fdisk_warnx(cxt, _("Partition %u doesn't end on cylinder boundary."), i+1);
|
|
if (lens[i]) {
|
|
for (j = 0; j < i; j++)
|
|
if (lens[j]) {
|
|
if (starts[j] == starts[i]+lens[i]) {
|
|
starts[j] = starts[i]; lens[j] += lens[i];
|
|
lens[i] = 0;
|
|
} else if (starts[i] == starts[j]+lens[j]){
|
|
lens[j] += lens[i];
|
|
lens[i] = 0;
|
|
} else if (!k) {
|
|
if (starts[i] < starts[j]+lens[j] &&
|
|
starts[j] < starts[i]+lens[i]) {
|
|
starto = starts[i];
|
|
if (starts[j] > starto)
|
|
starto = starts[j];
|
|
endo = starts[i]+lens[i];
|
|
if (starts[j]+lens[j] < endo)
|
|
endo = starts[j]+lens[j];
|
|
fdisk_warnx(cxt, _("Partition %u overlaps with others in "
|
|
"sectors %u-%u."), i+1, starto, endo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_QSORT_R
|
|
for (i = 0; i < SUN_MAXPARTITIONS; i++) {
|
|
if (lens[i])
|
|
array[i] = i;
|
|
else
|
|
array[i] = -1;
|
|
}
|
|
verify_sun_starts = starts;
|
|
|
|
qsort_r(array,ARRAY_SIZE(array),sizeof(array[0]),
|
|
(int (*)(const void *,const void *,void *)) verify_sun_cmp,
|
|
verify_sun_starts);
|
|
|
|
if (array[0] == -1) {
|
|
fdisk_info(cxt, _("No partitions defined."));
|
|
return 0;
|
|
}
|
|
stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors;
|
|
if (starts[array[0]])
|
|
fdisk_warnx(cxt, _("Unused gap - sectors 0-%u."), starts[array[0]]);
|
|
for (i = 0; i < 7 && array[i+1] != -1; i++) {
|
|
fdisk_warnx(cxt, _("Unused gap - sectors %u-%u."),
|
|
(starts[array[i]] + lens[array[i]]),
|
|
starts[array[i+1]]);
|
|
}
|
|
start = (starts[array[i]] + lens[array[i]]);
|
|
if (start < stop)
|
|
fdisk_warnx(cxt, _("Unused gap - sectors %u-%u."), start, stop);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int is_free_sector(struct fdisk_context *cxt,
|
|
fdisk_sector_t s, uint32_t starts[], uint32_t lens[])
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < cxt->label->nparts_max; i++) {
|
|
if (lens[i] && starts[i] <= s
|
|
&& starts[i] + lens[i] > s)
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int sun_add_partition(
|
|
struct fdisk_context *cxt,
|
|
struct fdisk_partition *pa,
|
|
size_t *partno)
|
|
{
|
|
struct sun_disklabel *sunlabel = self_disklabel(cxt);
|
|
uint32_t starts[SUN_MAXPARTITIONS], lens[SUN_MAXPARTITIONS];
|
|
struct sun_partition *part;
|
|
struct sun_info *info;
|
|
uint32_t start, stop, stop2;
|
|
int whole_disk = 0;
|
|
int sys = pa && pa->type ? pa->type->code : SUN_TAG_LINUX_NATIVE;
|
|
int rc;
|
|
size_t n;
|
|
|
|
char mesg[256];
|
|
size_t i;
|
|
unsigned int first, last;
|
|
|
|
rc = fdisk_partition_next_partno(pa, cxt, &n);
|
|
if (rc)
|
|
return rc;
|
|
|
|
part = &sunlabel->partitions[n];
|
|
info = &sunlabel->vtoc.infos[n];
|
|
|
|
if (part->num_sectors && be16_to_cpu(info->id) != SUN_TAG_UNASSIGNED) {
|
|
fdisk_info(cxt, _("Partition %zu is already defined. Delete "
|
|
"it before re-adding it."), n + 1);
|
|
return -EINVAL;
|
|
}
|
|
|
|
fetch_sun(cxt, starts, lens, &start, &stop);
|
|
|
|
if (stop <= start) {
|
|
if (n == 2)
|
|
whole_disk = 1;
|
|
else {
|
|
fdisk_info(cxt, _("Other partitions already cover the "
|
|
"whole disk. Delete some/shrink them before retry."));
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
if (pa && pa->start_follow_default)
|
|
first = start;
|
|
else if (pa && fdisk_partition_has_start(pa)) {
|
|
first = pa->start;
|
|
|
|
if (!whole_disk && !is_free_sector(cxt, first, starts, lens))
|
|
return -ERANGE;
|
|
} else {
|
|
struct fdisk_ask *ask;
|
|
|
|
snprintf(mesg, sizeof(mesg), _("First %s"),
|
|
fdisk_get_unit(cxt, FDISK_SINGULAR));
|
|
for (;;) {
|
|
ask = fdisk_new_ask();
|
|
if (!ask)
|
|
return -ENOMEM;
|
|
|
|
fdisk_ask_set_query(ask, mesg);
|
|
fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
|
|
|
|
if (whole_disk) {
|
|
fdisk_ask_number_set_low(ask, 0); /* minimal */
|
|
fdisk_ask_number_set_default(ask, 0); /* default */
|
|
fdisk_ask_number_set_high(ask, 0); /* maximal */
|
|
} else {
|
|
fdisk_ask_number_set_low(ask, fdisk_scround(cxt, start)); /* minimal */
|
|
fdisk_ask_number_set_default(ask, fdisk_scround(cxt, start)); /* default */
|
|
fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop)); /* maximal */
|
|
}
|
|
rc = fdisk_do_ask(cxt, ask);
|
|
first = fdisk_ask_number_get_result(ask);
|
|
fdisk_unref_ask(ask);
|
|
if (rc)
|
|
return rc;
|
|
|
|
if (fdisk_use_cylinders(cxt))
|
|
first *= fdisk_get_units_per_sector(cxt);
|
|
|
|
/* ewt asks to add: "don't start a partition at cyl 0"
|
|
However, edmundo@rano.demon.co.uk writes:
|
|
"In addition to having a Sun partition table, to be able to
|
|
boot from the disc, the first partition, /dev/sdX1, must
|
|
start at cylinder 0. This means that /dev/sdX1 contains
|
|
the partition table and the boot block, as these are the
|
|
first two sectors of the disc. Therefore you must be
|
|
careful what you use /dev/sdX1 for. In particular, you must
|
|
not use a partition starting at cylinder 0 for Linux swap,
|
|
as that would overwrite the partition table and the boot
|
|
block. You may, however, use such a partition for a UFS
|
|
or EXT2 file system, as these file systems leave the first
|
|
1024 bytes undisturbed. */
|
|
/* On the other hand, one should not use partitions
|
|
starting at block 0 in an md, or the label will
|
|
be trashed. */
|
|
if (!is_free_sector(cxt, first, starts, lens) && !whole_disk) {
|
|
if (n == 2 && !first) {
|
|
whole_disk = 1;
|
|
break;
|
|
}
|
|
fdisk_warnx(cxt, _("Sector %d is already allocated"), first);
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (n == 2 && first != 0)
|
|
fdisk_warnx(cxt, _("It is highly recommended that the "
|
|
"third partition covers the whole disk "
|
|
"and is of type `Whole disk'"));
|
|
|
|
if (!fdisk_use_cylinders(cxt)) {
|
|
/* Starting sector has to be properly aligned */
|
|
int cs = cxt->geom.heads * cxt->geom.sectors;
|
|
int x = first % cs;
|
|
|
|
if (x) {
|
|
fdisk_info(cxt, _("Aligning the first sector from %u to %u "
|
|
"to be on cylinder boundary."),
|
|
first, first + cs - x);
|
|
first += cs - x;
|
|
}
|
|
}
|
|
|
|
stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors; /* ancient */
|
|
stop2 = stop;
|
|
for (i = 0; i < cxt->label->nparts_max; i++) {
|
|
if (starts[i] > first && starts[i] < stop)
|
|
stop = starts[i];
|
|
}
|
|
|
|
/* last */
|
|
if (pa && pa->end_follow_default)
|
|
last = whole_disk || (n == 2 && !first) ? stop2 : stop;
|
|
else if (pa && fdisk_partition_has_size(pa)) {
|
|
last = first + pa->size - 1ULL;
|
|
|
|
if (!whole_disk && last > stop)
|
|
return -ERANGE;
|
|
} else {
|
|
struct fdisk_ask *ask = fdisk_new_ask();
|
|
|
|
if (!ask)
|
|
return -ENOMEM;
|
|
|
|
snprintf(mesg, sizeof(mesg),
|
|
_("Last %s or +%s or +size{K,M,G,T,P}"),
|
|
fdisk_get_unit(cxt, FDISK_SINGULAR),
|
|
fdisk_get_unit(cxt, FDISK_PLURAL));
|
|
fdisk_ask_set_query(ask, mesg);
|
|
fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
|
|
|
|
if (whole_disk) {
|
|
fdisk_ask_number_set_low(ask, fdisk_scround(cxt, stop2)); /* minimal */
|
|
fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop2)); /* default */
|
|
fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop2)); /* maximal */
|
|
fdisk_ask_number_set_base(ask, 0);
|
|
} else if (n == 2 && !first) {
|
|
fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */
|
|
fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop2)); /* default */
|
|
fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop2)); /* maximal */
|
|
fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first));
|
|
} else {
|
|
fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */
|
|
fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop)); /* default */
|
|
fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop)); /* maximal */
|
|
fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first));
|
|
}
|
|
|
|
if (fdisk_use_cylinders(cxt))
|
|
fdisk_ask_number_set_unit(ask,
|
|
cxt->sector_size *
|
|
fdisk_get_units_per_sector(cxt));
|
|
else
|
|
fdisk_ask_number_set_unit(ask, cxt->sector_size);
|
|
|
|
rc = fdisk_do_ask(cxt, ask);
|
|
last = fdisk_ask_number_get_result(ask);
|
|
|
|
fdisk_unref_ask(ask);
|
|
if (rc)
|
|
return rc;
|
|
if (fdisk_use_cylinders(cxt))
|
|
last *= fdisk_get_units_per_sector(cxt);
|
|
}
|
|
|
|
if (n == 2 && !first) {
|
|
if (last >= stop2) {
|
|
whole_disk = 1;
|
|
last = stop2;
|
|
} else if (last > stop) {
|
|
fdisk_warnx(cxt,
|
|
_("You haven't covered the whole disk with the 3rd partition, but your value\n"
|
|
"%lu %s covers some other partition. Your entry has been changed\n"
|
|
"to %lu %s"),
|
|
(unsigned long) fdisk_scround(cxt, last), fdisk_get_unit(cxt, FDISK_SINGULAR),
|
|
(unsigned long) fdisk_scround(cxt, stop), fdisk_get_unit(cxt, FDISK_SINGULAR));
|
|
last = stop;
|
|
}
|
|
} else if (!whole_disk && last > stop)
|
|
last = stop;
|
|
|
|
if (whole_disk)
|
|
sys = SUN_TAG_WHOLEDISK;
|
|
|
|
set_partition(cxt, n, first, last, sys);
|
|
cxt->label->nparts_cur = count_used_partitions(cxt);
|
|
if (partno)
|
|
*partno = n;
|
|
return 0;
|
|
}
|
|
|
|
static int sun_delete_partition(struct fdisk_context *cxt,
|
|
size_t partnum)
|
|
{
|
|
struct sun_disklabel *sunlabel;
|
|
struct sun_partition *part;
|
|
struct sun_info *info;
|
|
unsigned int nsec;
|
|
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
sunlabel = self_disklabel(cxt);
|
|
part = &sunlabel->partitions[partnum];
|
|
info = &sunlabel->vtoc.infos[partnum];
|
|
|
|
if (partnum == 2 &&
|
|
be16_to_cpu(info->id) == SUN_TAG_WHOLEDISK &&
|
|
!part->start_cylinder &&
|
|
(nsec = be32_to_cpu(part->num_sectors))
|
|
== cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders)
|
|
fdisk_info(cxt, _("If you want to maintain SunOS/Solaris compatibility, "
|
|
"consider leaving this "
|
|
"partition as Whole disk (5), starting at 0, with %u "
|
|
"sectors"), nsec);
|
|
info->id = cpu_to_be16(SUN_TAG_UNASSIGNED);
|
|
part->num_sectors = 0;
|
|
cxt->label->nparts_cur = count_used_partitions(cxt);
|
|
fdisk_label_set_changed(cxt->label, 1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int sun_list_disklabel(struct fdisk_context *cxt)
|
|
{
|
|
struct sun_disklabel *sunlabel;
|
|
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
sunlabel = self_disklabel(cxt);
|
|
|
|
if (fdisk_is_details(cxt)) {
|
|
fdisk_info(cxt,
|
|
_("Label geometry: %d rpm, %d alternate and %d physical cylinders,\n"
|
|
" %d extra sects/cyl, interleave %d:1"),
|
|
be16_to_cpu(sunlabel->rpm),
|
|
be16_to_cpu(sunlabel->acyl),
|
|
be16_to_cpu(sunlabel->pcyl),
|
|
be16_to_cpu(sunlabel->apc),
|
|
be16_to_cpu(sunlabel->intrlv));
|
|
fdisk_info(cxt, _("Label ID: %s"), sunlabel->label_id);
|
|
fdisk_info(cxt, _("Volume ID: %s"),
|
|
*sunlabel->vtoc.volume_id ? sunlabel->vtoc.volume_id : _("<none>"));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct fdisk_parttype *sun_get_parttype(
|
|
struct fdisk_context *cxt,
|
|
size_t n)
|
|
{
|
|
struct sun_disklabel *sunlabel = self_disklabel(cxt);
|
|
struct fdisk_parttype *t;
|
|
|
|
if (n >= cxt->label->nparts_max)
|
|
return NULL;
|
|
|
|
t = fdisk_label_get_parttype_from_code(cxt->label,
|
|
be16_to_cpu(sunlabel->vtoc.infos[n].id));
|
|
return t ? : fdisk_new_unknown_parttype(be16_to_cpu(sunlabel->vtoc.infos[n].id), NULL);
|
|
}
|
|
|
|
|
|
static int sun_get_partition(struct fdisk_context *cxt, size_t n,
|
|
struct fdisk_partition *pa)
|
|
{
|
|
struct sun_disklabel *sunlabel;
|
|
struct sun_partition *part;
|
|
uint16_t flags;
|
|
uint32_t start, len;
|
|
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
if (n >= cxt->label->nparts_max)
|
|
return -EINVAL;
|
|
|
|
sunlabel = self_disklabel(cxt);
|
|
part = &sunlabel->partitions[n];
|
|
|
|
pa->used = part->num_sectors ? 1 : 0;
|
|
if (!pa->used)
|
|
return 0;
|
|
|
|
flags = be16_to_cpu(sunlabel->vtoc.infos[n].flags);
|
|
start = be32_to_cpu(part->start_cylinder)
|
|
* cxt->geom.heads * cxt->geom.sectors;
|
|
len = be32_to_cpu(part->num_sectors);
|
|
|
|
pa->type = sun_get_parttype(cxt, n);
|
|
if (pa->type && pa->type->code == SUN_TAG_WHOLEDISK)
|
|
pa->wholedisk = 1;
|
|
|
|
if (flags & SUN_FLAG_UNMNT || flags & SUN_FLAG_RONLY) {
|
|
if (asprintf(&pa->attrs, "%c%c",
|
|
flags & SUN_FLAG_UNMNT ? 'u' : ' ',
|
|
flags & SUN_FLAG_RONLY ? 'r' : ' ') < 0)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
pa->start = start;
|
|
pa->size = len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* fdisk_sun_set_alt_cyl:
|
|
* @cxt: context
|
|
*
|
|
* Sets number of alternative cylinders. This function uses libfdisk Ask API
|
|
* for dialog with user.
|
|
*
|
|
* Returns: 0 on success, <0 on error.
|
|
*/
|
|
int fdisk_sun_set_alt_cyl(struct fdisk_context *cxt)
|
|
{
|
|
struct sun_disklabel *sunlabel = self_disklabel(cxt);
|
|
uintmax_t res;
|
|
int rc = fdisk_ask_number(cxt, 0, /* low */
|
|
be16_to_cpu(sunlabel->acyl), /* default */
|
|
65535, /* high */
|
|
_("Number of alternate cylinders"), /* query */
|
|
&res); /* result */
|
|
if (rc)
|
|
return rc;
|
|
|
|
sunlabel->acyl = cpu_to_be16(res);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* fdisk_sun_set_xcyl:
|
|
* @cxt: context
|
|
*
|
|
* Sets number of extra sectors per cylinder. This function uses libfdisk Ask API
|
|
* for dialog with user.
|
|
*
|
|
* Returns: 0 on success, <0 on error.
|
|
*/
|
|
int fdisk_sun_set_xcyl(struct fdisk_context *cxt)
|
|
{
|
|
struct sun_disklabel *sunlabel = self_disklabel(cxt);
|
|
uintmax_t res;
|
|
int rc = fdisk_ask_number(cxt, 0, /* low */
|
|
be16_to_cpu(sunlabel->apc), /* default */
|
|
cxt->geom.sectors, /* high */
|
|
_("Extra sectors per cylinder"), /* query */
|
|
&res); /* result */
|
|
if (rc)
|
|
return rc;
|
|
sunlabel->apc = cpu_to_be16(res);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* fdisk_sun_set_ilfact:
|
|
* @cxt: context
|
|
*
|
|
* Sets interleave factor. This function uses libfdisk Ask API for dialog with
|
|
* user.
|
|
*
|
|
* Returns: 0 on success, <0 on error.
|
|
*/
|
|
int fdisk_sun_set_ilfact(struct fdisk_context *cxt)
|
|
{
|
|
struct sun_disklabel *sunlabel = self_disklabel(cxt);
|
|
uintmax_t res;
|
|
int rc = fdisk_ask_number(cxt, 1, /* low */
|
|
be16_to_cpu(sunlabel->intrlv), /* default */
|
|
32, /* high */
|
|
_("Interleave factor"), /* query */
|
|
&res); /* result */
|
|
if (rc)
|
|
return rc;
|
|
sunlabel->intrlv = cpu_to_be16(res);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* fdisk_sun_set_rspeed
|
|
* @cxt: context
|
|
*
|
|
* Sets rotation speed. This function uses libfdisk Ask API for dialog with
|
|
* user.
|
|
*
|
|
* Returns: 0 on success, <0 on error.
|
|
*/
|
|
int fdisk_sun_set_rspeed(struct fdisk_context *cxt)
|
|
{
|
|
struct sun_disklabel *sunlabel = self_disklabel(cxt);
|
|
uintmax_t res;
|
|
int rc = fdisk_ask_number(cxt, 1, /* low */
|
|
be16_to_cpu(sunlabel->rpm), /* default */
|
|
USHRT_MAX, /* high */
|
|
_("Rotation speed (rpm)"), /* query */
|
|
&res); /* result */
|
|
if (rc)
|
|
return rc;
|
|
sunlabel->rpm = cpu_to_be16(res);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* fdisk_sun_set_pcylcount
|
|
* @cxt: context
|
|
*
|
|
* Sets number of physical cylinders. This function uses libfdisk Ask API for
|
|
* dialog with user.
|
|
*
|
|
* Returns: 0 on success, <0 on error.
|
|
*/
|
|
int fdisk_sun_set_pcylcount(struct fdisk_context *cxt)
|
|
{
|
|
struct sun_disklabel *sunlabel = self_disklabel(cxt);
|
|
uintmax_t res;
|
|
int rc = fdisk_ask_number(cxt, 0, /* low */
|
|
be16_to_cpu(sunlabel->pcyl), /* default */
|
|
USHRT_MAX, /* high */
|
|
_("Number of physical cylinders"), /* query */
|
|
&res); /* result */
|
|
if (!rc)
|
|
return rc;
|
|
sunlabel->pcyl = cpu_to_be16(res);
|
|
return 0;
|
|
}
|
|
|
|
static int sun_write_disklabel(struct fdisk_context *cxt)
|
|
{
|
|
struct sun_disklabel *sunlabel;
|
|
unsigned short *ush;
|
|
unsigned short csum = 0;
|
|
const size_t sz = sizeof(struct sun_disklabel);
|
|
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
sunlabel = self_disklabel(cxt);
|
|
|
|
/* Maybe geometry has been modified */
|
|
sunlabel->nhead = cpu_to_be16(cxt->geom.heads);
|
|
sunlabel->nsect = cpu_to_be16(cxt->geom.sectors);
|
|
|
|
if (cxt->geom.cylinders != be16_to_cpu(sunlabel->ncyl))
|
|
sunlabel->ncyl = cpu_to_be16( cxt->geom.cylinders
|
|
- be16_to_cpu(sunlabel->acyl) );
|
|
|
|
ush = (unsigned short *) sunlabel;
|
|
|
|
while(ush < (unsigned short *)(&sunlabel->csum))
|
|
csum ^= *ush++;
|
|
sunlabel->csum = csum;
|
|
if (lseek(cxt->dev_fd, 0, SEEK_SET) < 0)
|
|
return -errno;
|
|
if (write_all(cxt->dev_fd, sunlabel, sz) != 0)
|
|
return -errno;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sun_set_partition(
|
|
struct fdisk_context *cxt,
|
|
size_t i,
|
|
struct fdisk_partition *pa)
|
|
{
|
|
struct sun_disklabel *sunlabel;
|
|
struct sun_partition *part;
|
|
struct sun_info *info;
|
|
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
sunlabel = self_disklabel(cxt);
|
|
|
|
if (i >= cxt->label->nparts_max)
|
|
return -EINVAL;
|
|
|
|
if (pa->type) {
|
|
struct fdisk_parttype *t = pa->type;
|
|
|
|
if (t->code > UINT16_MAX)
|
|
return -EINVAL;
|
|
|
|
if (i == 2 && t->code != SUN_TAG_WHOLEDISK)
|
|
fdisk_info(cxt, _("Consider leaving partition 3 as Whole disk (5),\n"
|
|
"as SunOS/Solaris expects it and even Linux likes it.\n"));
|
|
|
|
part = &sunlabel->partitions[i];
|
|
info = &sunlabel->vtoc.infos[i];
|
|
|
|
if (cxt->script == NULL &&
|
|
t->code == SUN_TAG_LINUX_SWAP && !part->start_cylinder) {
|
|
int yes, rc;
|
|
|
|
rc = fdisk_ask_yesno(cxt,
|
|
_("It is highly recommended that the partition at offset 0\n"
|
|
"is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
|
|
"there may destroy your partition table and bootblock.\n"
|
|
"Are you sure you want to tag the partition as Linux swap?"), &yes);
|
|
if (rc)
|
|
return rc;
|
|
if (!yes)
|
|
return 1;
|
|
}
|
|
|
|
switch (t->code) {
|
|
case SUN_TAG_SWAP:
|
|
case SUN_TAG_LINUX_SWAP:
|
|
/* swaps are not mountable by default */
|
|
info->flags |= cpu_to_be16(SUN_FLAG_UNMNT);
|
|
break;
|
|
default:
|
|
/* assume other types are mountable;
|
|
user can change it anyway */
|
|
info->flags &= ~cpu_to_be16(SUN_FLAG_UNMNT);
|
|
break;
|
|
}
|
|
info->id = cpu_to_be16(t->code);
|
|
}
|
|
|
|
if (fdisk_partition_has_start(pa))
|
|
sunlabel->partitions[i].start_cylinder =
|
|
cpu_to_be32(pa->start / (cxt->geom.heads * cxt->geom.sectors));
|
|
if (fdisk_partition_has_size(pa))
|
|
sunlabel->partitions[i].num_sectors = cpu_to_be32(pa->size);
|
|
|
|
fdisk_label_set_changed(cxt->label, 1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int sun_reset_alignment(struct fdisk_context *cxt __attribute__((__unused__)))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int sun_partition_is_used(
|
|
struct fdisk_context *cxt,
|
|
size_t i)
|
|
{
|
|
struct sun_disklabel *sunlabel;
|
|
|
|
assert(cxt);
|
|
assert(cxt->label);
|
|
assert(fdisk_is_label(cxt, SUN));
|
|
|
|
if (i >= cxt->label->nparts_max)
|
|
return 0;
|
|
|
|
sunlabel = self_disklabel(cxt);
|
|
return sunlabel->partitions[i].num_sectors ? 1 : 0;
|
|
}
|
|
|
|
static const struct fdisk_field sun_fields[] =
|
|
{
|
|
{ FDISK_FIELD_DEVICE, N_("Device"), 10, 0 },
|
|
{ FDISK_FIELD_START, N_("Start"), 5, FDISK_FIELDFL_NUMBER },
|
|
{ FDISK_FIELD_END, N_("End"), 5, FDISK_FIELDFL_NUMBER },
|
|
{ FDISK_FIELD_SECTORS, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER },
|
|
{ FDISK_FIELD_CYLINDERS,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER },
|
|
{ FDISK_FIELD_SIZE, N_("Size"), 5, FDISK_FIELDFL_NUMBER },
|
|
{ FDISK_FIELD_TYPEID, N_("Id"), 2, FDISK_FIELDFL_NUMBER },
|
|
{ FDISK_FIELD_TYPE, N_("Type"), 0.1, 0 },
|
|
{ FDISK_FIELD_ATTR, N_("Flags"), 0, FDISK_FIELDFL_NUMBER }
|
|
};
|
|
|
|
const struct fdisk_label_operations sun_operations =
|
|
{
|
|
.probe = sun_probe_label,
|
|
.write = sun_write_disklabel,
|
|
.verify = sun_verify_disklabel,
|
|
.create = sun_create_disklabel,
|
|
.list = sun_list_disklabel,
|
|
|
|
.get_part = sun_get_partition,
|
|
.set_part = sun_set_partition,
|
|
.add_part = sun_add_partition,
|
|
.del_part = sun_delete_partition,
|
|
|
|
.part_is_used = sun_partition_is_used,
|
|
.part_toggle_flag = sun_toggle_partition_flag,
|
|
|
|
.reset_alignment = sun_reset_alignment,
|
|
};
|
|
|
|
/*
|
|
* allocates SUN label driver
|
|
*/
|
|
struct fdisk_label *fdisk_new_sun_label(struct fdisk_context *cxt)
|
|
{
|
|
struct fdisk_label *lb;
|
|
struct fdisk_sun_label *sun;
|
|
|
|
assert(cxt);
|
|
|
|
sun = calloc(1, sizeof(*sun));
|
|
if (!sun)
|
|
return NULL;
|
|
|
|
/* initialize generic part of the driver */
|
|
lb = (struct fdisk_label *) sun;
|
|
lb->name = "sun";
|
|
lb->id = FDISK_DISKLABEL_SUN;
|
|
lb->op = &sun_operations;
|
|
lb->parttypes = sun_parttypes;
|
|
lb->nparttypes = ARRAY_SIZE(sun_parttypes) - 1;
|
|
lb->fields = sun_fields;
|
|
lb->nfields = ARRAY_SIZE(sun_fields);
|
|
lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY;
|
|
|
|
return lb;
|
|
}
|