summaryrefslogtreecommitdiffstats
path: root/libparted/arch/beos.c
diff options
context:
space:
mode:
Diffstat (limited to 'libparted/arch/beos.c')
-rw-r--r--libparted/arch/beos.c649
1 files changed, 649 insertions, 0 deletions
diff --git a/libparted/arch/beos.c b/libparted/arch/beos.c
new file mode 100644
index 0000000..df14b99
--- /dev/null
+++ b/libparted/arch/beos.c
@@ -0,0 +1,649 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2006-2007, 2009-2014, 2019-2023 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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+
+/* POSIX headers */
+#include <sys/stat.h>
+#include <dirent.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* BeOS APIs */
+#include <drivers/Drivers.h>
+
+/* ZETA R1+ APIs */
+#if B_ZETA_VERSION >= B_ZETA_VERSION_1_0_0
+# include <device/ata_info.h>
+#endif
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "../architecture.h"
+
+#define BEOS_SPECIFIC(dev) ((BEOSSpecific*) (dev)->arch_specific)
+
+typedef struct _BEOSSpecific BEOSSpecific;
+
+struct _BEOSSpecific {
+ int fd;
+};
+
+static void
+_scan_for_disks(const char* path)
+{
+ char subdir[PATH_MAX];
+ dirent_t* entp;
+ size_t pos;
+ DIR* dirp;
+
+ if ((dirp=opendir(path)) != NULL)
+ {
+ /* Build first part of path */
+ strcpy(subdir, path);
+ strcat(subdir, "/");
+ pos = strlen(subdir);
+
+ /* Check all directory entries.. */
+ while((entp=readdir(dirp)) != NULL)
+ {
+ /* If they start with '.' just skip */
+ if (entp->d_name[0] == '.')
+ continue;
+
+ strcpy(subdir+pos, entp->d_name);
+
+ /* /dev/disk/.../raw are the complete disks
+ we're interested in */
+ if (strcmp(entp->d_name, "raw") == 0)
+ _ped_device_probe(subdir);
+ else /* If not 'raw', it most often will
+ be another subdir */
+ _scan_for_disks(subdir);
+ }
+
+ closedir(dirp);
+ }
+}
+
+static void
+_flush_cache(PedDevice* dev)
+{
+ int fd;
+ if ((fd=open(dev->path, O_RDONLY)) < 0)
+ {
+ ioctl(fd, B_FLUSH_DRIVE_CACHE);
+ close(fd);
+ }
+}
+
+#if B_ZETA_VERSION >= B_ZETA_VERSION_1_0_0
+static int
+_device_init_ata(PedDevice* dev)
+{
+ ata_device_infoblock ide_info;
+ int maxlen, len, idx, fd;
+ char buf[256];
+
+ /* Try and get information about device from ATA(PI) driver */
+ if ((fd=open(dev->path, O_RDONLY)) < 0)
+ goto ata_error;
+
+ if (ioctl(fd, B_ATA_GET_DEVICE_INFO, &ide_info, sizeof(ide_info)) < 0)
+ goto ata_error_close;
+
+ close(fd);
+
+ /* Copy 'logical' dimensions */
+ dev->bios_geom.cylinders = ide_info.cylinders;
+ dev->bios_geom.heads = ide_info.heads;
+ dev->bios_geom.sectors = ide_info.sectors;
+
+ /* Copy used dimensions */
+ dev->hw_geom.cylinders = ide_info.current_cylinders;
+ dev->hw_geom.heads = ide_info.current_heads;
+ dev->hw_geom.sectors = ide_info.current_sectors;
+
+ /* Copy total number of sectors */
+ if (ide_info._48_bit_addresses_supported)
+ dev->length = ide_info.LBA48_total_sectors;
+ else if (ide_info.LBA_supported)
+ dev->length = ide_info.LBA_total_sectors;
+ else
+ dev->length = ide_info.cylinders *
+ ide_info.heads *
+ ide_info.sectors;
+
+ dev->sector_size =
+ dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
+
+ /* Use sensible model */
+ maxlen=sizeof(ide_info.model_number);
+ strncpy(buf, ide_info.model_number, maxlen);
+ buf[maxlen] = '\0';
+
+ for (len=-1, idx=maxlen-1; idx > 0 && len < 0; idx--)
+ if (buf[idx] > 0x20)
+ len = idx;
+
+ buf[(len == -1) ? 0 : len+1] = '\0';
+
+ dev->model = strdup(buf);
+
+ return PED_DEVICE_IDE;
+
+ata_error_close:
+ close(fd);
+
+ata_error:
+ return 0;
+}
+#endif
+
+static int
+_device_init_generic_blkdev(PedDevice* dev)
+{
+ device_geometry bios, os;
+ int got_bios_info = 0;
+ int fd;
+
+ /* Try and get information about device from ATA(PI) driver */
+ if ((fd=open(dev->path, O_RDONLY)) < 0)
+ goto blkdev_error;
+
+ /* B_GET_GEOMETRY is mandatory */
+ if (ioctl(fd, B_GET_GEOMETRY, &os, sizeof(os)) < 0)
+ goto blkdev_error_close;
+
+ /* B_GET_BIOS_GEOMETRY is optional */
+ if (!ioctl(fd, B_GET_BIOS_GEOMETRY, &bios, sizeof(bios)))
+ got_bios_info = 1;
+
+ close(fd);
+
+ dev->hw_geom.cylinders = os.cylinder_count;
+ dev->hw_geom.heads = os.head_count;
+ dev->hw_geom.sectors = os.sectors_per_track;
+
+ dev->sector_size =
+ dev->phys_sector_size = os.bytes_per_sector;
+
+ if (got_bios_info)
+ {
+ dev->bios_geom.cylinders = bios.cylinder_count;
+ dev->bios_geom.heads = bios.head_count;
+ dev->bios_geom.sectors = bios.sectors_per_track;
+ }
+ else
+ dev->bios_geom = dev->hw_geom;
+
+ dev->model = strdup("");
+
+ return PED_DEVICE_IDE;
+
+blkdev_error_close:
+ close(fd);
+
+blkdev_error:
+ return 0;
+}
+
+static int
+_device_init_blkdev(PedDevice* dev)
+{
+ int type;
+
+#if B_ZETA_VERSION >= B_ZETA_VERSION_1_0_0
+ if (!(type=_device_init_ata(dev)))
+#endif
+ type = _device_init_generic_blkdev(dev);
+
+ return type;
+}
+
+static int
+_device_init_file(PedDevice* dev, struct stat* dev_statp)
+{
+ if (!dev_statp->st_size)
+ return 0;
+
+ dev->sector_size =
+ dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
+
+ dev->length = dev_statp->st_size / PED_SECTOR_SIZE_DEFAULT;
+
+ dev->bios_geom.cylinders = dev->length / (4 * 32);
+ dev->bios_geom.heads = 4;
+ dev->bios_geom.sectors = 32;
+ dev->hw_geom = dev->bios_geom;
+
+ dev->model = strdup(_("Disk Image"));
+
+ return PED_DEVICE_FILE;
+}
+
+static int
+_device_init(PedDevice* dev)
+{
+ struct stat dev_stat;
+ int type = 0;
+
+ /* Check if we're a regular file */
+ if (stat(dev->path, &dev_stat) < 0)
+ goto done;
+
+ if (S_ISBLK(dev_stat.st_mode) || S_ISCHR(dev_stat.st_mode))
+ type = _device_init_blkdev(dev);
+ else if (S_ISREG(dev_stat.st_mode))
+ type = _device_init_file(dev,&dev_stat);
+
+done:
+ return type;
+}
+
+
+static PedDevice*
+beos_new (const char* path)
+{
+ struct stat stat_info;
+ PedDevice* dev;
+
+ PED_ASSERT(path != NULL);
+
+ dev = (PedDevice*) ped_malloc (sizeof (PedDevice));
+ if (!dev)
+ goto error;
+
+ dev->path = strdup(path);
+ if (!dev->path)
+ goto error_free_dev;
+
+ dev->arch_specific
+ = (BEOSSpecific*) ped_malloc(sizeof(BEOSSpecific));
+ if (dev->arch_specific == NULL)
+ goto error_free_path;
+
+ dev->open_count = 0;
+ dev->read_only = 0;
+ dev->external_mode = 0;
+ dev->dirty = 0;
+ dev->boot_dirty = 0;
+
+ if ((dev->type=_device_init(dev)) <= 0)
+ goto error_free_arch_specific;
+
+ /* All OK! */
+ return dev;
+
+error_free_arch_specific:
+ free (dev->arch_specific);
+
+error_free_path:
+ free (dev->path);
+
+error_free_dev:
+ free (dev);
+
+error:
+ return NULL;
+}
+
+static void
+beos_destroy (PedDevice* dev)
+{
+ free (dev->arch_specific);
+ free (dev->path);
+ free (dev->model);
+ free (dev);
+}
+
+static int
+beos_is_busy (PedDevice* dev)
+{
+ return 1;
+}
+
+static int
+beos_open (PedDevice* dev)
+{
+ BEOSSpecific* arch_specific = BEOS_SPECIFIC(dev);
+
+retry:
+ arch_specific->fd = open(dev->path, O_RDWR);
+ if (arch_specific->fd == -1) {
+ char* rw_error_msg = strerror(errno);
+
+ arch_specific->fd = open (dev->path, O_RDONLY);
+ if (arch_specific->fd == -1) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_RETRY_CANCEL,
+ _("Error opening %s: %s"),
+ dev->path, strerror (errno))
+ != PED_EXCEPTION_RETRY) {
+ return 0;
+ } else {
+ goto retry;
+ }
+ } else {
+ ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_OK,
+ _("Unable to open %s read-write (%s). %s has "
+ "been opened read-only."),
+ dev->path, rw_error_msg, dev->path);
+ dev->read_only = 1;
+ }
+ } else {
+ dev->read_only = 0;
+ }
+
+ _flush_cache (dev);
+
+ return 1;
+}
+
+static int
+beos_refresh_open (PedDevice* dev)
+{
+ return 1;
+}
+
+static int
+beos_close (PedDevice* dev)
+{
+ BEOSSpecific* arch_specific = BEOS_SPECIFIC(dev);
+
+ if (dev->dirty)
+ _flush_cache (dev);
+
+ close (arch_specific->fd);
+
+ return 1;
+}
+
+static int
+beos_refresh_close (PedDevice* dev)
+{
+ if (dev->dirty)
+ _flush_cache (dev);
+
+ return 1;
+}
+
+static int
+beos_read (const PedDevice* dev, void* buffer, PedSector start, PedSector count)
+{
+ BEOSSpecific* arch_specific = BEOS_SPECIFIC(dev);
+ int status;
+ PedExceptionOption ex_status;
+ size_t read_length = count * dev->sector_size;
+
+ PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
+
+ /* First, try to seek */
+ while(1)
+ {
+ if (lseek(arch_specific->fd, start * dev->sector_size, SEEK_SET)
+ == start * dev->sector_size)
+ break;
+
+ ex_status = ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_RETRY_IGNORE_CANCEL,
+ _("%s during seek for read on %s"),
+ strerror (errno), dev->path);
+
+ switch (ex_status)
+ {
+ case PED_EXCEPTION_IGNORE:
+ return 1;
+ case PED_EXCEPTION_RETRY:
+ break /* out of switch */;
+ case PED_EXCEPTION_UNHANDLED:
+ ped_exception_catch ();
+ case PED_EXCEPTION_CANCEL:
+ return 0;
+ }
+ }
+
+ /* If we seeked ok, now is the time to read */
+ while (1)
+ {
+ status = read(arch_specific->fd, buffer, read_length);
+ if (status == count * dev->sector_size)
+ break;
+
+ if (status > 0)
+ {
+ read_length -= status;
+ buffer += status;
+ continue;
+ }
+
+ ex_status = ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_RETRY_IGNORE_CANCEL,
+ _("%s during read on %s"),
+ strerror (errno),
+ dev->path);
+
+ switch (ex_status)
+ {
+ case PED_EXCEPTION_IGNORE:
+ return 1;
+ case PED_EXCEPTION_RETRY:
+ break;
+ case PED_EXCEPTION_UNHANDLED:
+ ped_exception_catch ();
+ case PED_EXCEPTION_CANCEL:
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int
+beos_write (PedDevice* dev, const void* buffer, PedSector start,
+ PedSector count)
+{
+ BEOSSpecific* arch_specific = BEOS_SPECIFIC(dev);
+ int status;
+ PedExceptionOption ex_status;
+ size_t write_length = count * dev->sector_size;
+
+ PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
+
+ if (dev->read_only)
+ {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Can't write to %s, because it is opened read-only."),
+ dev->path)
+ != PED_EXCEPTION_IGNORE)
+ return 0;
+ else
+ return 1;
+ }
+
+ while(1)
+ {
+ if (lseek(arch_specific->fd,start * dev->sector_size,SEEK_SET)
+ == start * dev->sector_size)
+ break;
+
+ ex_status = ped_exception_throw (
+ PED_EXCEPTION_ERROR, PED_EXCEPTION_RETRY_IGNORE_CANCEL,
+ _("%s during seek for write on %s"),
+ strerror (errno), dev->path);
+
+ switch (ex_status)
+ {
+ case PED_EXCEPTION_IGNORE:
+ return 1;
+ case PED_EXCEPTION_RETRY:
+ break;
+ case PED_EXCEPTION_UNHANDLED:
+ ped_exception_catch ();
+ case PED_EXCEPTION_CANCEL:
+ return 0;
+ }
+ }
+
+#ifdef READ_ONLY
+ printf ("ped_device_write (\"%s\", %p, %d, %d)\n",
+ dev->path, buffer, (int) start, (int) count);
+#else
+ dev->dirty = 1;
+ while(1)
+ {
+ status = write (arch_specific->fd, buffer, write_length);
+ if (status == count * dev->sector_size)
+ break;
+
+ if (status > 0)
+ {
+ write_length -= status;
+ buffer += status;
+ continue;
+ }
+
+ ex_status = ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_RETRY_IGNORE_CANCEL,
+ _("%s during write on %s"),
+ strerror (errno), dev->path);
+
+ switch (ex_status)
+ {
+ case PED_EXCEPTION_IGNORE:
+ return 1;
+ case PED_EXCEPTION_RETRY:
+ break;
+ case PED_EXCEPTION_UNHANDLED:
+ ped_exception_catch ();
+ case PED_EXCEPTION_CANCEL:
+ return 0;
+ }
+ }
+#endif /* !READ_ONLY */
+
+ return 1;
+}
+
+static PedSector
+beos_check (PedDevice* dev, void* buffer, PedSector start, PedSector count)
+{
+ BEOSSpecific* arch_specific = BEOS_SPECIFIC(dev);
+ PedSector done = 0;
+ int status;
+
+ PED_ASSERT(dev != NULL);
+
+ if (lseek(arch_specific->fd, start * dev->sector_size, SEEK_SET)
+ != start * dev->sector_size)
+ return 0;
+
+ for (done = 0; done < count; done += status / dev->sector_size)
+ {
+ status = read (arch_specific->fd, buffer,
+ (size_t) ((count-done) * dev->sector_size));
+ if (status < 0)
+ break;
+ }
+
+ return done;
+}
+
+static int
+beos_sync (PedDevice* dev)
+{
+ return 1;
+}
+
+static int
+beos_sync_fast (PedDevice* dev)
+{
+ return 1;
+}
+
+/* Probe for all available disks */
+static void
+beos_probe_all ()
+{
+ /* For BeOS/ZETA/Haiku, all disks are published under /dev/disk */
+ _scan_for_disks("/dev/disk");
+}
+
+static char*
+beos_partition_get_path (const PedPartition* part)
+{
+ return NULL;
+}
+
+static int
+beos_partition_is_busy (const PedPartition* part)
+{
+ return 0;
+}
+
+static int
+beos_disk_commit (PedDisk* disk)
+{
+ return 0;
+}
+
+static PedDeviceArchOps beos_dev_ops = {
+ _new: beos_new,
+ destroy: beos_destroy,
+ is_busy: beos_is_busy,
+ open: beos_open,
+ refresh_open: beos_refresh_open,
+ close: beos_close,
+ refresh_close: beos_refresh_close,
+ read: beos_read,
+ write: beos_write,
+ check: beos_check,
+ sync: beos_sync,
+ sync_fast: beos_sync_fast,
+ probe_all: beos_probe_all
+};
+
+static PedDiskArchOps beos_disk_ops = {
+ partition_get_path: beos_partition_get_path,
+ partition_is_busy: beos_partition_is_busy,
+ disk_commit: beos_disk_commit
+};
+
+PedArchitecture ped_beos_arch = {
+ dev_ops: &beos_dev_ops,
+ disk_ops: &beos_disk_ops
+};