Logo Search packages:      
Sourcecode: parted version File versions

disk_bsd.c

/* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-

    libparted - a library for manipulating disk partitions
    Copyright (C) 2000, 2001 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 <msw@redhat.com>
*/

#include "config.h"

#include <string.h>

#include <parted/parted.h>
#include <parted/debug.h>
#include <parted/endian.h>

#if ENABLE_NLS
#  include <libintl.h>
#  define _(String) dgettext (PACKAGE, String)
#else
#  define _(String) (String)
#endif /* ENABLE_NLS */

/* struct's & #define's stolen from libfdisk, which probably came from
 * Linux...
 */

#define BSD_DISKMAGIC   (0x82564557UL)    /* The disk magic number */
#define BSD_MAXPARTITIONS     8
#define BSD_FS_UNUSED         0     /* disklabel unused partition entry ID */
#define BSD_LABEL_OFFSET      64

#define     BSD_DTYPE_SMD           1           /* SMD, XSMD; VAX hp/up */
#define     BSD_DTYPE_MSCP          2           /* MSCP */
#define     BSD_DTYPE_DEC           3           /* other DEC (rk, rl) */
#define     BSD_DTYPE_SCSI          4           /* SCSI */
#define     BSD_DTYPE_ESDI          5           /* ESDI interface */
#define     BSD_DTYPE_ST506         6           /* ST506 etc. */
#define     BSD_DTYPE_HPIB          7           /* CS/80 on HP-IB */
#define BSD_DTYPE_HPFL        8           /* HP Fiber-link */
#define     BSD_DTYPE_FLOPPY  10          /* floppy */

#define     BSD_BBSIZE  8192        /* size of boot area, with label */
#define     BSD_SBSIZE  8192        /* max size of fs superblock */

typedef struct _BSDRawPartition           BSDRawPartition;
typedef struct _BSDRawLabel         BSDRawLabel;

struct _BSDRawPartition {           /* the partition table */
      uint32_t    p_size;           /* number of sectors in partition */
      uint32_t    p_offset;   /* starting sector */
      uint32_t    p_fsize;    /* filesystem basic fragment size */
      uint8_t           p_fstype;   /* filesystem type, see below */
      uint8_t           p_frag;           /* filesystem fragments per block */
      uint16_t    p_cpg;            /* filesystem cylinders per group */
} __attribute__((packed));

struct _BSDRawLabel {
      uint32_t    d_magic;          /* the magic number */
      int16_t           d_type;                 /* drive type */
      int16_t           d_subtype;        /* controller/d_type specific */
      int8_t            d_typename[16];         /* type name, e.g. "eagle" */
      int8_t            d_packname[16];         /* pack identifier */ 
      uint32_t    d_secsize;        /* # of bytes per sector */
      uint32_t    d_nsectors;       /* # of data sectors per track */
      uint32_t    d_ntracks;        /* # of tracks per cylinder */
      uint32_t    d_ncylinders;           /* # of data cylinders per unit */
      uint32_t    d_secpercyl;            /* # of data sectors per cylinder */
      uint32_t    d_secperunit;           /* # of data sectors per unit */
      uint16_t    d_sparespertrack; /* # of spare sectors per track */
      uint16_t    d_sparespercyl;         /* # of spare sectors per cylinder */
      uint32_t    d_acylinders;           /* # of alt. cylinders per unit */
      uint16_t    d_rpm;                  /* rotational speed */
      uint16_t    d_interleave;           /* hardware sector interleave */
      uint16_t    d_trackskew;            /* sector 0 skew, per track */
      uint16_t    d_cylskew;        /* sector 0 skew, per cylinder */
      uint32_t    d_headswitch;           /* head switch time, usec */
      uint32_t    d_trkseek;        /* track-to-track seek, usec */
      uint32_t    d_flags;          /* generic flags */
#define NDDATA 5
      uint32_t    d_drivedata[NDDATA];    /* drive-type specific information */
#define NSPARE 5
      uint32_t    d_spare[NSPARE];  /* reserved for future use */
      uint32_t    d_magic2;         /* the magic number (again) */
      uint16_t    d_checksum;       /* xor of data incl. partitions */
      
      /* filesystem and partition information: */
      uint16_t    d_npartitions;          /* number of partitions in following */
      uint32_t    d_bbsize;         /* size of boot area at sn0, bytes */
      uint32_t    d_sbsize;         /* max size of fs superblock, bytes */
      BSDRawPartition d_partitions[BSD_MAXPARTITIONS];      /* actually may be more */
} __attribute__((packed));

typedef struct {
      char        boot_code [512];
} BSDDiskData;

typedef struct {
      uint8_t           type;
} BSDPartitionData;

static PedDiskType bsd_disk_type;

/* XXX fixme: endian? */
static unsigned short
xbsd_dkcksum (BSDRawLabel *lp) {
      unsigned short *start, *end;
      unsigned short sum = 0;
      
      lp->d_checksum = 0;
      start = (u_short*) lp;
      end = (u_short*) &lp->d_partitions [
                        PED_LE16_TO_CPU (lp->d_npartitions)];
      while (start < end)
            sum ^= *start++;
      return sum;
}

/* XXX fixme: endian? */
static void
alpha_bootblock_checksum (char *boot) {
      uint64_t *dp, sum;
      int i;
      
      dp = (uint64_t *)boot;
      sum = 0;
      for (i = 0; i < 63; i++)
            sum += dp[i];
      dp[63] = sum;
}


static int
bsd_probe (PedDevice *dev)
{
      char        boot[512];
      BSDRawLabel *label;
      int         i;

      PED_ASSERT (dev != NULL, return 0);

      if (!ped_device_read (dev, boot, 0, 1))
            return 0;

      label = (BSDRawLabel *) (boot + BSD_LABEL_OFFSET);

      alpha_bootblock_checksum(boot);
      
      /* check magic */
      if (PED_LE32_TO_CPU (label->d_magic) != BSD_DISKMAGIC)
            return 0;

      return 1;
}

static PedDisk*
bsd_alloc (PedDevice* dev)
{
      PedDisk*    disk;
      BSDDiskData*      bsd_specific;
      BSDRawLabel*      label;

      disk = _ped_disk_alloc (dev, &bsd_disk_type);
      if (!disk)
            goto error;
      disk->disk_specific = bsd_specific = ped_malloc (sizeof (BSDDiskData));
      if (!bsd_specific)
            goto error_free_disk;

      label = (BSDRawLabel*) (bsd_specific->boot_code + BSD_LABEL_OFFSET);
      memset(label, 0, sizeof(BSDRawLabel));

      label->d_magic = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
      label->d_type = PED_CPU_TO_LE16 (BSD_DTYPE_SCSI);
      label->d_flags = 0;
      label->d_secsize = PED_CPU_TO_LE16 (PED_SECTOR_SIZE);
      label->d_nsectors = PED_CPU_TO_LE32 (dev->bios_geom.sectors);
      label->d_ntracks = PED_CPU_TO_LE32 (dev->bios_geom.heads);
      label->d_ncylinders = PED_CPU_TO_LE32 (dev->bios_geom.cylinders);
      label->d_secpercyl = PED_CPU_TO_LE32 (dev->bios_geom.sectors
                                    * dev->bios_geom.heads);
      label->d_secperunit
            = PED_CPU_TO_LE32 (dev->bios_geom.sectors
                           * dev->bios_geom.heads
                           * dev->bios_geom.cylinders);
      
      label->d_rpm = PED_CPU_TO_LE16 (3600);
      label->d_interleave = PED_CPU_TO_LE16 (1);;
      label->d_trackskew = 0;
      label->d_cylskew = 0;
      label->d_headswitch = 0;
      label->d_trkseek = 0;
      
      label->d_magic2 = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
      label->d_bbsize = PED_CPU_TO_LE32 (BSD_BBSIZE);
      label->d_sbsize = PED_CPU_TO_LE32 (BSD_SBSIZE);
      
      label->d_npartitions = 0;
      label->d_checksum = xbsd_dkcksum (label);
      return disk;

error_free_disk:
      ped_free (disk);
error:
      return NULL;
}

static PedDisk*
bsd_duplicate (const PedDisk* disk)
{
      PedDisk*    new_disk;
      BSDDiskData*      new_bsd_data;
      BSDDiskData*      old_bsd_data = (BSDDiskData*) disk->disk_specific;
       
      new_disk = ped_disk_new_fresh (disk->dev, &bsd_disk_type);
      if (!new_disk)
            return NULL;

      new_bsd_data = (BSDDiskData*) new_disk->disk_specific;
      memcpy (new_bsd_data->boot_code, old_bsd_data->boot_code, 512);
      return new_disk;
}

static void
bsd_free (PedDisk* disk)
{
      ped_free (disk->disk_specific);
      _ped_disk_free (disk);
}

#ifndef DISCOVER_ONLY
static int
bsd_clobber (PedDevice* dev)
{
      char        boot [512];
      BSDRawLabel*      label = (BSDRawLabel *) (boot + BSD_LABEL_OFFSET);

      if (!ped_device_read (dev, boot, 0, 1))
            return 0;
      label->d_magic = 0;
      return ped_device_write (dev, (void*) boot, 0, 1);
}
#endif /* !DISCOVER_ONLY */

static int
bsd_read (PedDisk* disk)
{
      BSDDiskData*      bsd_specific = (BSDDiskData*) disk->disk_specific;
      BSDRawLabel*      label;
      int         i;
      
      ped_disk_delete_all (disk);

      if (!ped_device_read (disk->dev, bsd_specific->boot_code, 0, 1))
            goto error;
      label = (BSDRawLabel *) (bsd_specific->boot_code + BSD_LABEL_OFFSET);

      for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
            PedPartition*           part;
            BSDPartitionData* bsd_part_data;
            PedSector         start;
            PedSector         end;
            PedConstraint*          constraint_exact;

            if (!label->d_partitions[i - 1].p_size
                || !label->d_partitions[i - 1].p_fstype)
                  continue;
            start = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset);
            end = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset)
                  + PED_LE32_TO_CPU(label->d_partitions[i - 1].p_size) - 1;
            part = ped_partition_new (disk, 0, NULL, start, end);
            if (!part)
                  goto error;
            bsd_part_data = part->disk_specific;
            bsd_part_data->type = label->d_partitions[i - 1].p_fstype;
            part->num = i;
            part->fs_type = ped_file_system_probe (&part->geom);
            
            constraint_exact = ped_constraint_exact (&part->geom);
            if (!ped_disk_add_partition (disk, part, constraint_exact))
                  goto error;
            ped_constraint_destroy (constraint_exact);
      }

      return 1;

error:
      return 0;
}

static void
_probe_and_add_boot_code (PedDisk* disk)
{
      BSDDiskData*            bsd_specific;
      BSDRawLabel*            old_label;
      char              old_boot_code [512];

      bsd_specific = (BSDDiskData*) disk->disk_specific;
      old_label = (BSDRawLabel*) (old_boot_code + BSD_LABEL_OFFSET);

      if (!ped_device_read (disk->dev, old_boot_code, 0, 1))
            return;
      if (old_boot_code [0]
          && old_label->d_magic == PED_CPU_TO_LE32 (BSD_DISKMAGIC))
            memcpy (bsd_specific->boot_code, old_boot_code, 512);
}

#ifndef DISCOVER_ONLY
static int
bsd_write (PedDisk* disk)
{
      BSDDiskData*            bsd_specific;
      BSDRawLabel*            label;
      BSDPartitionData* bsd_data;
      PedPartition*           part;
      int               i;
      int               max_part = 0;

      PED_ASSERT (disk != NULL, return 0);
      PED_ASSERT (disk->dev != NULL, return 0);

      bsd_specific = (BSDDiskData*) disk->disk_specific;
      label = (BSDRawLabel *) (bsd_specific->boot_code + BSD_LABEL_OFFSET);

      if (!bsd_specific->boot_code [0])
            _probe_and_add_boot_code (disk);

      memset (label->d_partitions, 0,
            sizeof (BSDRawPartition) * BSD_MAXPARTITIONS);

      for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
            part = ped_disk_get_partition (disk, i);
            if (!part)
                  continue;
            bsd_data = part->disk_specific;
            label->d_partitions[i - 1].p_fstype = bsd_data->type;
            label->d_partitions[i - 1].p_offset
                  = PED_CPU_TO_LE32 (part->geom.start);
            label->d_partitions[i - 1].p_size
                  = PED_CPU_TO_LE32 (part->geom.length);
            max_part = i;
      }

      label->d_npartitions = PED_CPU_TO_LE16 (max_part) + 1;
      label->d_checksum = xbsd_dkcksum (label);

      alpha_bootblock_checksum (bsd_specific->boot_code);

      if (!ped_device_write (disk->dev, (void*) bsd_specific->boot_code,
                         0, 1))
            goto error;
      return ped_device_sync (disk->dev);

error:
      return 0;
}
#endif /* !DISCOVER_ONLY */

static PedPartition*
bsd_partition_new (const PedDisk* disk, PedPartitionType part_type,
               const PedFileSystemType* fs_type,
               PedSector start, PedSector end)
{
      PedPartition*           part;
      BSDPartitionData* bsd_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
                        = bsd_data = ped_malloc (sizeof (BSDPartitionData));
            if (!bsd_data)
                  goto error_free_part;
            bsd_data->type = 0;
      } else {
            part->disk_specific = NULL;
      }
      return part;

error_free_bsd_data:
      ped_free (bsd_data);
error_free_part:
      ped_free (part);
error:
      return 0;
}

static PedPartition*
bsd_partition_duplicate (const PedPartition* part)
{
      PedPartition*           new_part;
      BSDPartitionData* new_bsd_data;
      BSDPartitionData* old_bsd_data;

      new_part = ped_partition_new (part->disk, part->type,
                              part->fs_type, part->geom.start,
                              part->geom.end);
      if (!new_part)
            return NULL;
      new_part->num = part->num;

      old_bsd_data = (BSDPartitionData*) part->disk_specific;
      new_bsd_data = (BSDPartitionData*) new_part->disk_specific;
      new_bsd_data->type = old_bsd_data->type;
      return new_part;
}

static void
bsd_partition_destroy (PedPartition* part)
{
      PED_ASSERT (part != NULL, return);

      if (ped_partition_is_active (part))
            ped_free (part->disk_specific);
      _ped_partition_free (part);
}

static int
bsd_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
{
      BSDPartitionData* bsd_data = part->disk_specific;

      part->fs_type = fs_type;

      if (!fs_type)
            bsd_data->type = 0x8;
      else if (!strcmp (fs_type->name, "linux-swap"))
            bsd_data->type = 0x1;
      else
            bsd_data->type = 0x8;

      return 1;
}

static int
bsd_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
{
      /* no flags for bsd */
      return 0;
}

static int
bsd_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
{
      /* no flags for bsd */
      return 0;
}

static int
bsd_partition_is_flag_available (const PedPartition* part,
                         PedPartitionFlag flag)
{
      /* no flags for bsd */
      return 0;
}


static int
bsd_get_max_primary_partition_count (const PedDisk* disk)
{
      return BSD_MAXPARTITIONS;
}

static PedConstraint*
_get_constraint (const PedDevice* dev)
{
      PedGeometry max;

      ped_geometry_init (&max, dev, 1, dev->length - 1);
      return ped_constraint_new_from_max (&max);
}

static int
bsd_partition_align (PedPartition* part, const PedConstraint* constraint)
{
      if (_ped_partition_attempt_align (part, constraint,
                                _get_constraint (part->disk->dev)))
                  return 1;

#ifndef DISCOVER_ONLY
      ped_exception_throw (
            PED_EXCEPTION_ERROR,
            PED_EXCEPTION_CANCEL,
            _("Unable to satisfy all constraints on the partition."));
#endif
      return 0;
}

static int
bsd_partition_enumerate (PedPartition* part)
{
      int i;
      PedPartition* p;
      
      /* never change the partition numbers */
      if (part->num != -1)
            return 1;
      for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
            p = ped_disk_get_partition (part->disk, i);
            if (!p) {
                  part->num = i;
                  return 1;
            }
      }

      /* failed to allocate a number */
#ifndef DISCOVER_ONLY
      ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
                       _("Unable to allocate a bsd disklabel slot"));
#endif
      return 0;
}

static int
bsd_alloc_metadata (PedDisk* disk)
{
      PedPartition*           new_part;
      PedConstraint*          constraint_any = NULL;

      PED_ASSERT (disk != NULL, goto error);
      PED_ASSERT (disk->dev != NULL, goto error);

      constraint_any = ped_constraint_any (disk->dev);

      /* allocate 1 sector for the disk label at the start */
      new_part = ped_partition_new (disk, 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;
}

static PedDiskOps bsd_disk_ops = {
      probe:                  bsd_probe,
#ifndef DISCOVER_ONLY
      clobber:          bsd_clobber,
#else
      clobber:          NULL,
#endif
      alloc:                  bsd_alloc,
      duplicate:        bsd_duplicate,
      free:             bsd_free,
      read:             bsd_read,
#ifndef DISCOVER_ONLY
      write:                  bsd_write,
#else
      write:                  NULL,
#endif

      partition_new:          bsd_partition_new,
      partition_duplicate:    bsd_partition_duplicate,
      partition_destroy:      bsd_partition_destroy,
      partition_set_system:   bsd_partition_set_system,
      partition_set_flag:     bsd_partition_set_flag,
      partition_get_flag:     bsd_partition_get_flag,
      partition_is_flag_available:  bsd_partition_is_flag_available,
      partition_set_name:     NULL,
      partition_get_name:     NULL,
      partition_align:  bsd_partition_align,
      partition_enumerate:    bsd_partition_enumerate,

      alloc_metadata:         bsd_alloc_metadata,
      get_max_primary_partition_count:
                        bsd_get_max_primary_partition_count
};

static PedDiskType bsd_disk_type = {
      next:       NULL,
      name:       "bsd",
      ops:        &bsd_disk_ops,
      features:   0
};

void
ped_disk_bsd_init ()
{
      PED_ASSERT (sizeof (BSDRawPartition) == 16, return);
      PED_ASSERT (sizeof (BSDRawLabel) == 276, return);

      ped_register_disk_type (&bsd_disk_type);
}

void
ped_disk_bsd_done ()
{
      ped_unregister_disk_type (&bsd_disk_type);
}

Generated by  Doxygen 1.6.0   Back to index