/* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
libparted - a library for manipulating disk partitions
Copyright (C) 1998-2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contributor: Matt Wilson
*/
#include "config.h"
#include
#include
#include
#include
#include
#if ENABLE_NLS
# define _(String) gettext (String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
#define SUN_LABEL_MAGIC 0xDABE
#define SUN_LABEL_OFFSET 0
#define SUN_MAXPARTITIONS 8
typedef struct _SunRawPartition SunRawPartition;
typedef struct _SunRawInfo SunRawInfo;
typedef struct _SunRawLabel SunRawLabel;
struct _SunRawPartition {
unsigned int start_cylinder;
unsigned int num_sectors;
};
struct _SunRawInfo {
unsigned char spare1;
unsigned char id;
unsigned char spare2;
unsigned char flags;
};
struct _SunRawLabel {
unsigned char info[128]; /* Informative text string */
unsigned char spare0[14];
SunRawInfo infos[SUN_MAXPARTITIONS];
unsigned char spare1[246]; /* Boot information etc. */
unsigned short rspeed; /* Disk rotational speed */
unsigned short pcylcount; /* Physical cylinder count */
unsigned short sparecyl; /* extra sects per cylinder */
unsigned char spare2[4]; /* More magic... */
unsigned short ilfact; /* Interleave factor */
unsigned short ncyl; /* Data cylinder count */
unsigned short nacyl; /* Alt. cylinder count */
unsigned short ntrks; /* Tracks per cylinder */
unsigned short nsect; /* Sectors per track */
unsigned char spare3[4]; /* Even more magic... */
SunRawPartition parts[SUN_MAXPARTITIONS];
unsigned short magic; /* Magic number */
unsigned short csum; /* Label xor'd checksum */
};
static int sun_probe (const PedDevice *dev);
static PedDisk* sun_open (PedDevice* dev);
static PedDisk* sun_create (PedDevice* dev);
static int sun_clobber (PedDevice* dev);
static int sun_close (PedDisk* disk);
static int sun_read (PedDisk* disk);
static int sun_write (PedDisk* disk);
static PedPartition* sun_partition_new (
const PedDisk* disk, PedPartitionType part_type,
const PedFileSystemType* fs_type, PedSector start, PedSector end);
static void sun_partition_destroy (PedPartition* part);
static int sun_partition_set_flag (
PedPartition* part, PedPartitionFlag flag, int state);
static int sun_partition_get_flag (
const PedPartition* part, PedPartitionFlag flag);
static int sun_partition_is_flag_available (
const PedPartition* part,
PedPartitionFlag flag);
static int sun_partition_align (PedPartition* part,
const PedConstraint* constraint);
static int sun_partition_enumerate (PedPartition* part);
static int sun_partition_set_extended_system (PedPartition* part);
static int sun_get_max_primary_partition_count (const PedDisk* disk);
static int sun_alloc_metadata (PedDisk* disk);
static PedDiskOps sun_disk_ops = {
probe: sun_probe,
open: sun_open,
create: sun_create,
clobber: sun_clobber,
close: sun_close,
read: sun_read,
write: sun_write,
partition_new: sun_partition_new,
partition_destroy: sun_partition_destroy,
partition_set_flag: sun_partition_set_flag,
partition_get_flag: sun_partition_get_flag,
partition_is_flag_available: sun_partition_is_flag_available,
partition_set_name: NULL,
partition_get_name: NULL,
partition_align: sun_partition_align,
partition_enumerate: sun_partition_enumerate,
partition_set_extended_system: sun_partition_set_extended_system,
alloc_metadata: sun_alloc_metadata,
get_max_primary_partition_count:
sun_get_max_primary_partition_count
};
static PedDiskType sun_disk_type = {
next: NULL,
name: "sun",
ops: &sun_disk_ops,
features: 0
};
void
ped_disk_sun_init ()
{
PED_ASSERT (sizeof (SunRawLabel) == 512, return);
ped_register_disk_type (&sun_disk_type);
}
void
ped_disk_sun_done ()
{
ped_unregister_disk_type (&sun_disk_type);
}
static int
sun_probe (const PedDevice *dev)
{
PedDiskType* disk_type;
char boot[512];
SunRawLabel *label;
int i;
PED_ASSERT (dev != NULL, return 0);
if (!ped_device_open ((PedDevice*) dev))
return 0;
if (!ped_device_read (dev, boot, 0, 1)) {
ped_device_close ((PedDevice*) dev);
return 0;
}
ped_device_close ((PedDevice*) dev);
label = (SunRawLabel *) (boot + SUN_LABEL_OFFSET);
/* check magic */
if (PED_BE16_TO_CPU (label->magic) != SUN_LABEL_MAGIC)
return 0;
return 1;
}
static PedDisk*
sun_open (PedDevice* dev)
{
PedDisk* disk;
PED_ASSERT (dev != NULL, return 0);
if (!sun_probe (dev))
goto error;
if (!ped_device_open ((PedDevice*) dev))
goto error;
disk = ped_disk_alloc (dev, &sun_disk_type);
if (!disk)
goto error;
if (!sun_read (disk))
goto error_free_disk;
return disk;
error_free_disk:
ped_disk_free (disk);
error:
return NULL;
}
static int
sun_close (PedDisk* disk)
{
PED_ASSERT (disk != NULL, return 0);
ped_device_close (disk->dev);
ped_disk_free (disk);
return 1;
}
static PedDisk*
sun_create (PedDevice* dev)
{
char boot[512];
SunRawLabel* label;
unsigned short* sp;
PED_ASSERT (dev != NULL, return 0);
if (!ped_device_open ((PedDevice*) dev))
goto error;
if (!ped_device_read (dev, boot, 0, 1)) {
ped_device_close ((PedDevice*) dev);
return 0;
}
label = (SunRawLabel *) (boot + SUN_LABEL_OFFSET);
memset(label, 0, sizeof(label));
label->magic = PED_CPU_TO_BE16 (SUN_LABEL_MAGIC);
label->rspeed = 5400;
label->nacyl = 2;
label->sparecyl = 0;
label->ilfact = 1;
label->pcylcount = PED_CPU_TO_BE16 (dev->cylinders);
label->ncyl = PED_CPU_TO_BE16 (dev->cylinders);
label->ntrks = PED_CPU_TO_BE16 (dev->heads);
label->ncyl = PED_CPU_TO_BE16 (dev->cylinders);
label->ntrks = PED_CPU_TO_BE16 (dev->heads);
label->nsect = PED_CPU_TO_BE16 (dev->sectors);
/* create compatibility whole disk partition */
label->parts[2].start_cylinder = 0;
label->parts[2].num_sectors = PED_CPU_TO_BE32(dev->cylinders *
dev->heads *
dev->sectors);
label->infos[2].id = 5;
strcpy (label->info, "PartEd created partition table");
/* XXX endian */
label->csum = 0;
for (sp = (unsigned short *) label; sp < &label->csum; sp++)
label->csum ^= *sp;
if (!ped_device_write (dev, (void*) boot, 0, 1))
goto error_close_dev;
if (!ped_device_sync (dev))
goto error_close_dev;
ped_device_close (dev);
return sun_open (dev);
error_close_dev:
ped_device_close (dev);
error:
return 0;
}
static int
sun_clobber (PedDevice* dev)
{
char boot[512];
SunRawLabel *label;
PED_ASSERT (dev != NULL, return 0);
PED_ASSERT (sun_probe (dev), return 0);
if (!ped_device_open ((PedDevice*) dev))
goto error;
if (!ped_device_read (dev, boot, 0, 1))
goto error_close_dev;
label = (SunRawLabel *) (boot + SUN_LABEL_OFFSET);
label->magic = 0;
if (!ped_device_write (dev, (void*) boot, 0, 1))
goto error_close_dev;
ped_device_close (dev);
return 1;
error_close_dev:
ped_device_close (dev);
error:
return 0;
}
static int
sun_read (PedDisk* disk)
{
char boot[512];
SunRawLabel *label;
SunPartitionData* sun_data;
int i, s;
PedPartition* part;
PedSector start, end;
PedConstraint* constraint_exact;
PED_ASSERT (disk != NULL, return 0);
PED_ASSERT (disk->dev != NULL, return 0);
ped_disk_delete_all (disk);
if (!ped_device_open ((PedDevice*) disk->dev))
goto error;
if (!ped_device_read (disk->dev, boot, 0, 1))
goto error_close_dev;
label = (SunRawLabel *) (boot + SUN_LABEL_OFFSET);
for (i = 1; i <= SUN_MAXPARTITIONS; i++) {
if (!label->parts[i - 1].num_sectors) continue;
start = PED_BE32_TO_CPU(label->parts[i - 1].start_cylinder) *
PED_BE16_TO_CPU(label->nsect) *
PED_BE16_TO_CPU(label->ntrks);
end = start + PED_BE32_TO_CPU(label->parts[i - 1].num_sectors) - 1;
part = ped_partition_new (disk, PED_PARTITION_PRIMARY, NULL,
start, end);
if (!part)
goto error_close_dev;
sun_data = part->disk_specific;
sun_data->type = label->infos[i - 1].id;
part->num = i;
part->fs_type = ped_file_system_probe (&part->geom);
constraint_exact = ped_constraint_exact (part);
if (!ped_disk_add_partition (disk, part, constraint_exact))
goto error_close_dev;
ped_constraint_destroy (constraint_exact);
}
ped_device_close ((PedDevice*) disk->dev);
return 1;
error_close_dev:
ped_device_close ((PedDevice*) disk->dev);
error:
return 0;
}
static int
sun_write (PedDisk* disk)
{
SunRawLabel *label;
SunPartitionData* sun_data;
PedPartition* part;
int i, max_part;
char boot[512];
unsigned short * sp;
PED_ASSERT (disk != NULL, return 0);
PED_ASSERT (disk->dev != NULL, return 0);
if (!ped_device_read (disk->dev, boot, 0, 1))
return 0;
label = (SunRawLabel *) (boot + SUN_LABEL_OFFSET);
memset (label->infos, 0,
sizeof (SunRawInfo) * SUN_MAXPARTITIONS);
memset (label->parts, 0,
sizeof (SunRawPartition) * SUN_MAXPARTITIONS);
for (i = 1; i <= SUN_MAXPARTITIONS; i++) {
part = ped_disk_get_partition (disk, i);
if (!part)
continue;
sun_data = part->disk_specific;
label->infos[i - 1].id = sun_data->type;
label->parts[i - 1].start_cylinder = PED_CPU_TO_BE32 (part->geom.start /
(PED_BE16_TO_CPU(label->nsect) *
PED_BE16_TO_CPU(label->ntrks)));
label->parts[i - 1].num_sectors = PED_CPU_TO_BE32 (part->geom.length);
}
label->csum = 0;
/* XXX endian */
for (sp = (unsigned short *) label; sp < &label->csum; sp++)
label->csum ^= *sp;
if (!ped_device_write (disk->dev, (void*) boot, 0, 1))
return 0;
if (!ped_device_sync (disk->dev))
return 0;
return 1;
}
static PedPartition*
sun_partition_new (const PedDisk* disk, PedPartitionType part_type,
const PedFileSystemType* fs_type,
PedSector start, PedSector end)
{
PedPartition* part;
SunPartitionData* sun_data;
part = ped_partition_alloc (disk, part_type, fs_type, start, end);
if (!part)
goto error;
if (ped_partition_is_active (part)) {
part->disk_specific
= sun_data = ped_malloc (sizeof (SunPartitionData));
if (!sun_data)
goto error_free_part;
sun_data->type = 0;
if (fs_type && !ped_partition_set_system (part, fs_type))
goto error_free_sun_data;
} else {
part->disk_specific = NULL;
}
return part;
error_free_sun_data:
ped_free (sun_data);
error_free_part:
ped_free (part);
error:
return 0;
}
static void
sun_partition_destroy (PedPartition* part)
{
PED_ASSERT (part != NULL, return);
if (ped_partition_is_active (part))
ped_free (part->disk_specific);
ped_free (part);
}
static int
sun_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
{
/* no flags for sun */
return 0;
}
static int
sun_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
{
/* no flags for sun */
return 0;
}
static int
sun_partition_is_flag_available (const PedPartition* part,
PedPartitionFlag flag)
{
/* no flags for sun */
return 0;
}
static int
sun_get_max_primary_partition_count (const PedDisk* disk)
{
return SUN_MAXPARTITIONS;
}
static int
sun_partition_set_extended_system (PedPartition* part)
{
return 1;
}
static int
sun_partition_align (PedPartition* part, const PedConstraint* constraint)
{
PedGeometry* new_geom;
new_geom = ped_constraint_solve_nearest (constraint, &part->geom);
if (!new_geom) {
ped_exception_throw (
PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
_("Unable to align partition."));
return 0;
}
ped_geometry_set (&part->geom, new_geom->start, new_geom->length);
ped_geometry_destroy (new_geom);
return 1;
}
static int
sun_partition_enumerate (PedPartition* part)
{
int i;
PedPartition* p;
/* never change the partition numbers */
if (part->num != -1)
return 1;
for (i = 1; i <= SUN_MAXPARTITIONS; i++) {
p = ped_disk_get_partition (part->geom.disk, i);
if (!p) {
part->num = i;
return 1;
}
}
/* failed to allocate a number */
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("Unable to allocate a sun disklabel slot"));
return 0;
}
static int
sun_alloc_metadata (PedDisk* disk)
{
PedPartition* new_part;
PedConstraint* constraint_any = ped_constraint_any (disk);
PED_ASSERT (disk != NULL, goto error);
PED_ASSERT (disk->dev != NULL, goto error);
/* allocate 1 sector for the disk label at the start */
new_part = ped_partition_new (
disk,
PED_PARTITION_PRIMARY | PED_PARTITION_METADATA,
NULL,
0, 0);
if (!new_part)
goto error;
if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
ped_partition_destroy (new_part);
goto error;
}
ped_constraint_destroy (constraint_any);
return 1;
error:
ped_constraint_destroy (constraint_any);
return 0;
}