Solaris support. --- /dev/null +++ parted-1.8.8/libparted/arch/solaris.c @@ -0,0 +1,1393 @@ +/* + libparted - a library for manipulating disk partitions + Copyright (C) 1999 - 2005 Free Software Foundation, Inc. + Copyright (C) 2007 Nikhil,Sujay,Nithin,Srivatsa. + + Bug fixes and completion of the module in 2009 by Mark.Logan@sun.com. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#include <sys/types.h> +#include <sys/mkdev.h> +#include "config.h" +#include "xalloc.h" +#include <sys/dkio.h> + +/* + * __attribute doesn't exist on solaris + */ +#define __attribute__(X) /* nothing */ + +#include <sys/vtoc.h> + +#include <parted/parted.h> +#include <parted/debug.h> +#include <parted/solaris.h> +#include <malloc.h> + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <libgen.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <unistd.h> +#include <dirent.h> +#include <libdiskmgt.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/swap.h> +#include <sys/mnttab.h> +#include <sys/mntent.h> + +#if ENABLE_NLS +#include <libintl.h> +#define _(String) dgettext(PACKAGE, String) +#else +#define _(String) (String) +#endif /* ENABLE_NLS */ + +#ifndef UINT_MAX64 +#define UINT_MAX64 0xffffffffffffffffULL +#endif + +/* + * Macro to convert a device number into a partition number + */ +#define PARTITION(dev) (minor(dev) & 0x07) + + +char * +canonicalize_file_name(const char *name) +{ + char *buf; + + buf = malloc(MAXPATHLEN); + if (!buf) { + errno = ENOMEM; + return (NULL); + } + + return (strcpy(buf, name)); +} + +static int +_device_stat(PedDevice* dev, struct stat *dev_stat) +{ + PED_ASSERT(dev != NULL, return (0)); + PED_ASSERT(!dev->external_mode, return (0)); + + while (1) { + if (!stat(dev->path, dev_stat)) { + return (1); + } else { + if (ped_exception_throw( + PED_EXCEPTION_ERROR, + PED_EXCEPTION_RETRY_CANCEL, + _("Could not stat device %s - %s."), + dev->path, strerror(errno)) != PED_EXCEPTION_RETRY) + return (0); + } + } +} + +static void +_device_set_length_and_sector_size(PedDevice* dev) +{ + SolarisSpecific* arch_specific; + PedSector size; + struct dk_minfo dk_minfo; + struct dk_geom dk_geom; + + PED_ASSERT(dev != NULL, return); + PED_ASSERT(dev->open_count > 0, return); + + arch_specific = SOLARIS_SPECIFIC(dev); + + dev->sector_size = PED_SECTOR_SIZE_DEFAULT; + dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT; + + /* this ioctl requires the raw device */ + if (ioctl(arch_specific->fd, DKIOCGMEDIAINFO, &dk_minfo) < 0) { + printf("_device_get_length: ioctl DKIOCGMEDIAINFO failed\n"); + ped_exception_throw( + PED_EXCEPTION_BUG, + PED_EXCEPTION_CANCEL, + _("Unable to determine the size of %s (%s)."), + dev->path, + strerror(errno)); + } else { + size = dk_minfo.dki_capacity; + dev->length = size; + dev->sector_size = dk_minfo.dki_lbsize; + if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) { + ped_exception_throw( + PED_EXCEPTION_WARNING, + PED_EXCEPTION_OK, + _("Device %s has a logical sector size of " + "%lld. Not all parts of GNU Parted support " + "this at the moment, and the working code " + "is HIGHLY EXPERIMENTAL.\n"), + dev->path, dev->sector_size); + } + if (size > 0) { + return; + } + } + + /* + * On some disks DKIOCGMEDIAINFO doesn't work, it returns 0, + * so try DKIOCG_PHYGEOM next. + */ + /* this ioctl requires the raw device */ + if (ioctl(arch_specific->fd, DKIOCG_PHYGEOM, &dk_geom) < 0) { + printf("_device_get_length: ioctl DKIOCG_PHYGEOM failed\n"); + ped_exception_throw( + PED_EXCEPTION_BUG, + PED_EXCEPTION_CANCEL, + _("Unable to determine the size of %s (%s)."), + dev->path, strerror(errno)); + + return; + } + + /* + * XXX For large disks, I am adding 16064 to the size of the disk. + * Solaris underreports the size of the disk, because it rounds down to + * a multiple of 16065. This causes a problem with Vista because Vista + * creates a partition that occupies the whole disk, including the + * blocks at the end of the disk that Solaris loses. + */ + if (dk_geom.dkg_nhead == 255 && dk_geom.dkg_nsect == 63) { + size = ((PedSector) dk_geom.dkg_pcyl * + (255 * 63)) + ((255*63)-1); + } else { + size = (PedSector) dk_geom.dkg_pcyl * + dk_geom.dkg_nhead * dk_geom.dkg_nsect; + } + + dev->length = size; +} + +static int +_device_probe_geometry(PedDevice* dev) +{ + SolarisSpecific* arch_specific; + struct stat dev_stat; + struct dk_geom dk_geom; + + PED_ASSERT(dev != NULL, return (0)); + PED_ASSERT(dev->open_count > 0, return (0)); + + arch_specific = SOLARIS_SPECIFIC(dev); + + _device_set_length_and_sector_size(dev); + if (dev->length == 0) { + printf("_device_probe_geometry: _device_get_length = 0\n"); + return (0); + } + + dev->bios_geom.sectors = 63; + dev->bios_geom.heads = 255; + dev->bios_geom.cylinders = dev->length / (63 * 255); + if ((ioctl(arch_specific->fd, DKIOCG_PHYGEOM, &dk_geom) >= 0) && + dk_geom.dkg_nsect && dk_geom.dkg_nhead) { + dev->hw_geom.sectors = dk_geom.dkg_nsect; + dev->hw_geom.heads = dk_geom.dkg_nhead; + dev->hw_geom.cylinders = dk_geom.dkg_pcyl; + } else { + perror("_device_probe_geometry: DKIOCG_PHYGEOM"); + dev->hw_geom = dev->bios_geom; + } + + return (1); +} + +static int +init_ide(PedDevice *dev) +{ + struct stat dev_stat; + + PED_ASSERT(dev != NULL, return (0)); + + if (!_device_stat(dev, &dev_stat)) { + printf("init_ide: _device_stat failed\n"); + goto error; + } + if (!ped_device_open(dev)) { + printf("init_ide: ped_device_open failed\n"); + goto error; + } + if (!_device_probe_geometry(dev)) { + printf("init_ide: _device_probe_geometry failed\n"); + goto error_close_dev; + } + + ped_device_close(dev); + return (1); + +error_close_dev: + ped_device_close(dev); +error: + return (0); +} + +static PedDevice* +solaris_new(const char *path) +{ + PedDevice* dev; + + PED_ASSERT(path != NULL, return (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 + = (SolarisSpecific*) ped_malloc(sizeof (SolarisSpecific)); + if (!dev->arch_specific) + goto error_free_path; + + dev->open_count = 0; + dev->read_only = 0; + dev->external_mode = 0; + dev->dirty = 0; + dev->boot_dirty = 0; + dev->model = strdup("Generic Ide"); + dev->type = PED_DEVICE_IDE; + if (!init_ide(dev)) { + goto error_free_arch_specific; + } + + return (dev); + +error_free_arch_specific: + ped_free(dev->arch_specific); + ped_free(dev->model); +error_free_path: + ped_free(dev->path); +error_free_dev: + ped_free(dev); +error: + return (NULL); +} + +static void +solaris_destroy(PedDevice* dev) +{ + PED_ASSERT(dev != NULL, return); + + ped_free(dev->arch_specific); + ped_free(dev->model); + ped_free(dev->path); + ped_free(dev); +} + +/* + * This function constructs the Solaris device name for + * partition num on a disk given the *p0 device for that disk. + * For example: partition 2 of /dev/dsk/c0d0p0 becomes /dev/dsk/c0d0p2. + */ +static char * +_device_get_part_path(PedDevice* dev, int num) +{ + int path_len = strlen(dev->path); + int result_len = path_len + 16; + char *result; + + PED_ASSERT(dev != NULL, return (NULL)); + PED_ASSERT(num >= 1, return (NULL)); + + result = (char *)ped_malloc(result_len); + if (!result) + return (NULL); + + strncpy(result, dev->path, result_len); + if (path_len > 10 && result[path_len - 2] == 'p' && + result[path_len - 1] == '0') { + (void) snprintf(result + path_len - 1, + result_len - path_len + 1, "%d", num); + } else { + (void) snprintf(result, result_len, "partition %d", num); + } + + return (result); +} + +static struct swaptable * +getswapentries(void) +{ + register struct swaptable *st; + register struct swapent *swapent; + int i, num; + char fullpathname[MAXPATHLEN]; + + /* + * get the number of swap entries + */ + if ((num = swapctl(SC_GETNSWP, (void *)NULL)) == -1) { + perror("getswapentries: swapctl SC_GETNSWP"); + return (NULL); + } + if (num == 0) + return (NULL); + if ((st = (swaptbl_t *)malloc(num * sizeof (swapent_t) + sizeof (int))) + == NULL) { + printf("getswapentries: malloc 1 failed.\n"); + return (NULL); + } + swapent = st->swt_ent; + for (i = 0; i < num; i++, swapent++) { + if ((swapent->ste_path = malloc(MAXPATHLEN)) == NULL) { + printf("getswapentries: malloc 2 failed.\n"); + goto error; + } + } + st->swt_n = num; + if ((num = swapctl(SC_LIST, (void *)st)) == -1) { + perror("getswapentries: swapctl SC_LIST"); + goto error; + } + swapent = st->swt_ent; + for (i = 0; i < num; i++, swapent++) { + if (*swapent->ste_path != '/') { + printf("getswapentries: %s\n", swapent->ste_path); + (void) snprintf(fullpathname, sizeof (fullpathname), + "/dev/%s", swapent->ste_path); + (void) strcpy(swapent->ste_path, fullpathname); + } + } + + return (st); + +error: + free(st); + return (NULL); +} + +static void +freeswapentries(st) +struct swaptable *st; +{ + register struct swapent *swapent; + int i; + + swapent = st->swt_ent; + for (i = 0; i < st->swt_n; i++, swapent++) + free(swapent->ste_path); + free(st); +} + +/* + * function getpartition: + */ +static int +getpartition(PedDevice* dev, char *pathname) +{ + SolarisSpecific* arch_specific; + int mfd; + struct dk_cinfo dkinfo; + struct dk_cinfo cur_disk_dkinfo; + struct stat stbuf; + char raw_device[MAXPATHLEN]; + int found = -1; + + PED_ASSERT(dev != NULL, return (found)); + PED_ASSERT(pathname != NULL, return (found)); + + arch_specific = SOLARIS_SPECIFIC(dev); + + /* + * Map the block device name to the raw device name. + * If it doesn't appear to be a device name, skip it. + */ + if (strncmp(pathname, "/dev/", 5)) + return (found); + (void) strcpy(raw_device, "/dev/r"); + (void) strcat(raw_device, pathname + strlen("/dev/")); + /* + * Determine if this appears to be a disk device. + * First attempt to open the device. If if fails, skip it. + */ + if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) { + return (found); + } + if (fstat(mfd, &stbuf) == -1) { + perror("getpartition: fstat raw_device"); + (void) close(mfd); + return (found); + } + /* + * Must be a character device + */ + if (!S_ISCHR(stbuf.st_mode)) { + printf("getpartition: not character device\n"); + (void) close(mfd); + return (found); + } + /* + * Attempt to read the configuration info on the disk. + */ + if (ioctl(mfd, DKIOCINFO, &dkinfo) < 0) { + perror("getpartition: ioctl DKIOCINFO raw_device"); + (void) close(mfd); + return (found); + } + /* + * Finished with the opened device + */ + (void) close(mfd); + + /* + * Now get the info about the current disk + */ + if (ioctl(arch_specific->fd, DKIOCINFO, &cur_disk_dkinfo) < 0) { + (void) close(mfd); + return (found); + } + + /* + * If it's not the disk we're interested in, it doesn't apply. + */ + if (cur_disk_dkinfo.dki_ctype != dkinfo.dki_ctype || + cur_disk_dkinfo.dki_cnum != dkinfo.dki_cnum || + cur_disk_dkinfo.dki_unit != dkinfo.dki_unit || + strcmp(cur_disk_dkinfo.dki_dname, dkinfo.dki_dname) != 0) { + return (found); + } + + /* + * Extract the partition that is mounted. + */ + return (PARTITION(stbuf.st_rdev)); +} + +/* + * This Routine checks to see if there are partitions used for swapping overlaps + * a given portion of a disk. If the start parameter is < 0, it means + * that the entire disk should be checked + */ +static int +checkswap(PedDevice* dev, diskaddr_t start, diskaddr_t end) +{ + SolarisSpecific* arch_specific; + struct extvtoc extvtoc; + struct swaptable *st; + struct swapent *swapent; + int i; + int found = 0; + int part; + diskaddr_t p_start; + diskaddr_t p_size; + + PED_ASSERT(dev != NULL, return (0)); + + arch_specific = SOLARIS_SPECIFIC(dev); + + if (ioctl(arch_specific->fd, DKIOCGEXTVTOC, &extvtoc) == -1) { + return (0); + } + + /* + * check for swap entries + */ + st = getswapentries(); + /* + * if there are no swap entries return. + */ + if (st == (struct swaptable *)NULL) + return (0); + swapent = st->swt_ent; + for (i = 0; i < st->swt_n; i++, swapent++) { + if ((part = getpartition(dev, swapent->ste_path)) != -1) { + if (start == UINT_MAX64) { + found = -1; + break; + } + p_start = extvtoc.v_part[part].p_start; + p_size = extvtoc.v_part[part].p_size; + if (start >= p_start + p_size || end < p_start) { + continue; + } + found = -1; + break; + } + } + freeswapentries(st); + + return (found); +} + +/* + * Determines if there are partitions that are a part of an SVM, VxVM, zpool + * volume or a live upgrade device, overlapping a given portion of a disk. + * Mounts and swap devices are checked in legacy format code. + */ +static int +checkdevinuse(PedDevice *dev, diskaddr_t start, diskaddr_t end, int print) +{ + int error; + int found = 0; + int check = 0; + int i; + int part = 0; + uint64_t slice_start, slice_size; + dm_descriptor_t *slices = NULL; + nvlist_t *attrs = NULL; + char *usage; + char *name; + char cur_disk_path[MAXPATHLEN]; + char *pcur_disk_path; + + PED_ASSERT(dev != NULL, return (found)); + + /* + * Truncate the characters following "d*", such as "s*" or "p*" + */ + strcpy(cur_disk_path, dev->path); + pcur_disk_path = basename(cur_disk_path); + name = strrchr(pcur_disk_path, 'd'); + if (name) { + name++; + for (; (*name <= '9') && (*name >= '0'); name++) + ; + *name = (char)0; + } + + /* + * For format, we get basic 'in use' details from libdiskmgt. After + * that we must do the appropriate checking to see if the 'in use' + * details require a bit of additional work. + */ + + dm_get_slices(pcur_disk_path, &slices, &error); + if (error) { + /* + * If ENODEV, it actually means the device is not in use. + * We will return (0) without displaying error. + */ + if (error != ENODEV) { + printf("checkdevinuse: Error1 occurred with device in " + "use checking: %s\n", strerror(error)); + return (found); + } + } + if (slices == NULL) + return (found); + + for (i = 0; slices[i] != 0; i++) { + /* + * If we are checking the whole disk + * then any and all in use data is + * relevant. + */ + if (start == UINT_MAX64) { + name = dm_get_name(slices[i], &error); + if (error != 0 || !name) { + printf("checkdevinuse: Error2 occurred with " + "device in use checking: %s\n", + strerror(error)); + continue; + } + printf("checkdevinuse: name1 %s\n", name); + if (dm_inuse(name, &usage, DM_WHO_FORMAT, &error) || + error) { + if (error != 0) { + dm_free_name(name); + name = NULL; + printf("checkdevinuse: Error3 " + "occurred with device " + "in use checking: %s\n", + strerror(error)); + continue; + } + dm_free_name(name); + name = NULL; + /* + * If this is a dump device, then it is + * a failure. You cannot format a slice + * that is a dedicated dump device. + */ + + if (strstr(usage, DM_USE_DUMP)) { + if (print) { + printf(usage); + free(usage); + } + dm_free_descriptors(slices); + return (1); + } + /* + * We really found a device that is in use. + * Set 'found' for the return value. + */ + found ++; + check = 1; + if (print) { + printf(usage); + free(usage); + } + } + } else { + /* + * Before getting the in use data, verify that the + * current slice is within the range we are checking. + */ + attrs = dm_get_attributes(slices[i], &error); + if (error) { + printf("checkdevinuse: Error4 occurred with " + "device in use checking: %s\n", + strerror(error)); + continue; + } + if (attrs == NULL) { + continue; + } + + (void) nvlist_lookup_uint64(attrs, DM_START, + &slice_start); + (void) nvlist_lookup_uint64(attrs, DM_SIZE, + &slice_size); + if (start >= (slice_start + slice_size) || + (end < slice_start)) { + nvlist_free(attrs); + attrs = NULL; + continue; + } + name = dm_get_name(slices[i], &error); + if (error != 0 || !name) { + printf("checkdevinuse: Error5 occurred with " + "device in use checking: %s\n", + strerror(error)); + nvlist_free(attrs); + attrs = NULL; + continue; + } + if (dm_inuse(name, &usage, + DM_WHO_FORMAT, &error) || error) { + if (error != 0) { + dm_free_name(name); + name = NULL; + printf("checkdevinuse: Error6 " + "occurred with device " + "in use checking: %s\n", + strerror(error)); + nvlist_free(attrs); + attrs = NULL; + continue; + } + dm_free_name(name); + name = NULL; + /* + * If this is a dump device, then it is + * a failure. You cannot format a slice + * that is a dedicated dump device. + */ + if (strstr(usage, DM_USE_DUMP)) { + if (print) { + printf(usage); + free(usage); + } + dm_free_descriptors(slices); + nvlist_free(attrs); + return (1); + } + /* + * We really found a device that is in use. + * Set 'found' for the return value. + */ + found ++; + check = 1; + if (print) { + printf(usage); + free(usage); + } + } + } + /* + * If check is set it means we found a slice(the current slice) + * on this device in use in some way. We potentially want + * to check this slice when labeling is requested. + */ + if (check) { + name = dm_get_name(slices[i], &error); + if (error != 0 || !name) { + printf("checkdevinuse: Error7 occurred with " + "device in use checking: %s\n", + strerror(error)); + nvlist_free(attrs); + attrs = NULL; + continue; + } + part = getpartition(dev, name); + dm_free_name(name); + name = NULL; + check = 0; + } + /* + * If we have attributes then we have successfully + * found the slice we were looking for and we also + * know this means we are not searching the whole + * disk so break out of the loop + * now. + */ + if (attrs) { + nvlist_free(attrs); + break; + } + } + + if (slices) { + dm_free_descriptors(slices); + } + + return (found); +} + +/* + * This routine checks to see if there are mounted partitions overlapping + * a given portion of a disk. If the start parameter is < 0, it means + * that the entire disk should be checked. + */ +static int +checkmount(PedDevice* dev, diskaddr_t start, diskaddr_t end) +{ + SolarisSpecific* arch_specific; + struct extvtoc extvtoc; + diskaddr_t p_start; + diskaddr_t p_size; + FILE *fp; + int found = 0; + int part; + struct mnttab mnt_record; + struct mnttab *mp = &mnt_record; + + PED_ASSERT(dev != NULL, return (found)); + + arch_specific = SOLARIS_SPECIFIC(dev); + + if (ioctl(arch_specific->fd, DKIOCGEXTVTOC, &extvtoc) == -1) { + return (0); + } + + /* + * Open the mount table. + */ + fp = fopen(MNTTAB, "r"); + if (fp == NULL) { + printf("checkmount: Unable to open mount table.\n"); + return (0); + } + /* + * Loop through the mount table until we run out of entries. + */ + while ((getmntent(fp, mp)) != -1) { + + if ((part = getpartition(dev, mp->mnt_special)) == -1) + continue; + + /* + * It's a mount on the disk we're checking. If we are + * checking whole disk, then we found trouble. We can + * quit searching. + */ + if (start == UINT_MAX64) { + found = -1; + break; + } + + /* + * If the partition overlaps the zone we're checking, + * then we found trouble. We can quit searching. + */ + p_start = extvtoc.v_part[part].p_start; + p_size = extvtoc.v_part[part].p_size; + if (start >= p_start + p_size || end < p_start) { + continue; + } + found = -1; + break; + } + /* + * Close down the mount table. + */ + (void) fclose(fp); + + return (found); +} + +/* + * Return 1 if the device is busy, 0 otherwise. + */ +static int +solaris_is_busy(PedDevice* dev) +{ + PED_ASSERT(dev != NULL, return (0)); + PED_ASSERT(dev->open_count > 0, return (0)); + + if (checkmount(dev, (diskaddr_t)-1, (diskaddr_t)-1)) + return (1); + + if (checkswap(dev, (diskaddr_t)-1, (diskaddr_t)-1)) + return (1); + + if (checkdevinuse(dev, (diskaddr_t)-1, (diskaddr_t)-1, 1)) + return (1); + + return (0); +} + +/* + * This will accept a dev->path that looks like this: + * /devices/pci@0,0/pci-ide@1f,2/ide@0/cmdk@0,0:q + * /devices/pci@0,0/pci-ide@1f,2/ide@0/cmdk@0,0:q,raw + * or this: + * /dev/dsk/c0d0p0 + * /dev/rdsk/c0d0p0 + * It has to open the raw device, so it converts to it locally, if necessary. + */ +static int +solaris_open(PedDevice* dev) +{ + SolarisSpecific* arch_specific; + char rawname[MAXPATHLEN]; + + PED_ASSERT(dev != NULL, return (0)); + + arch_specific = SOLARIS_SPECIFIC(dev); + + /* + * Convert to the raw device, unless it already is. + */ + if (strncmp(dev->path, "/devices", 8) == 0) { + if (strncmp(&dev->path[strlen(dev->path)-4], ",raw", 4)) { + snprintf(rawname, sizeof (rawname), "%s,raw", + dev->path); + } else { + strcpy(rawname, dev->path); + } + } else { + /* + * Assumes it is of the form: /dev/dsk/ or /dev/rdsk/ + */ + if (strncmp(dev->path, "/dev/dsk/", 9) == 0) { + snprintf(rawname, sizeof (rawname), "/dev/rdsk/%s", + &dev->path[9]); + } else { + strcpy(rawname, dev->path); + } + } + +retry: + arch_specific->fd = open(rawname, O_RDWR); + + if (arch_specific->fd == -1) { + char *rw_error_msg = strerror(errno); + + arch_specific->fd = open(rawname, O_RDONLY); + + if (arch_specific->fd == -1) { + printf("solaris_open: open(\"%s\") failed\n", rawname); + if (ped_exception_throw( + PED_EXCEPTION_ERROR, + PED_EXCEPTION_RETRY_CANCEL, + _("Error opening %s: %s"), + rawname, 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."), + rawname, rw_error_msg, rawname); + dev->read_only = 1; + } + } else { + dev->read_only = 0; + } + + return (1); +} + +static int +solaris_refresh_open(PedDevice* dev) +{ + return (1); +} + +static int +solaris_close(PedDevice* dev) +{ + SolarisSpecific* arch_specific; + + PED_ASSERT(dev != NULL, return (0)); + + arch_specific = SOLARIS_SPECIFIC(dev); + + close(arch_specific->fd); + return (1); +} + +static int +_do_fsync(PedDevice* dev) +{ + SolarisSpecific* arch_specific; + int status; + PedExceptionOption ex_status; + + PED_ASSERT(dev != NULL, return (0)); + PED_ASSERT(dev->open_count > 0, return (0)); + + arch_specific = SOLARIS_SPECIFIC(dev); + + while (1) { + status = fsync(arch_specific->fd); + if (status >= 0) + break; + + ex_status = ped_exception_throw( + PED_EXCEPTION_ERROR, + PED_EXCEPTION_RETRY_IGNORE_CANCEL, + _("%s during fsync 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 +solaris_refresh_close(PedDevice* dev) +{ + if (dev->dirty) + _do_fsync(dev); + return (1); +} + +static int +_device_seek(const PedDevice* dev, PedSector sector) +{ + SolarisSpecific* arch_specific; + + PED_ASSERT(dev != NULL, return (0)); + PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return (0)); + PED_ASSERT(dev->open_count > 0, return (0)); + PED_ASSERT(!dev->external_mode, return (0)); + + arch_specific = SOLARIS_SPECIFIC(dev); + + if (sizeof (off_t) < 8) { + off64_t pos = (off64_t)(sector * dev->sector_size); + return (lseek64(arch_specific->fd, pos, SEEK_SET) == pos); + } else { + off_t pos = sector * dev->sector_size; + return (lseek(arch_specific->fd, pos, SEEK_SET) == pos); + } +} + +static int +solaris_read(const PedDevice* dev, void* vbuffer, PedSector start, + PedSector count) +{ + SolarisSpecific* arch_specific; + int status; + PedExceptionOption ex_status; + size_t read_length = count * dev->sector_size; + void *diobuf; + char *buffer = vbuffer; + + PED_ASSERT(dev != NULL, return (0)); + PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return (0)); + PED_ASSERT(dev->open_count > 0, return (0)); + PED_ASSERT(!dev->external_mode, return (0)); + + arch_specific = SOLARIS_SPECIFIC(dev); + + while (1) { + if (_device_seek(dev, start)) + 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; + + case PED_EXCEPTION_UNHANDLED: + ped_exception_catch(); + case PED_EXCEPTION_CANCEL: + return (0); + } + } + + diobuf = memalign(dev->sector_size, read_length); + if (diobuf == NULL) { + printf("solaris_read: cannot memalign %u\n", read_length); + return (0); + } + + while (1) { + status = read(arch_specific->fd, diobuf, read_length); + + if (status > 0) + memcpy(buffer, diobuf, status); + + if (status == read_length) + break; + + if (status > 0) { + printf("solaris_read: partial read %d of %d\n", + status, read_length); + 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: + free(diobuf); + return (1); + + case PED_EXCEPTION_RETRY: + break; + + case PED_EXCEPTION_UNHANDLED: + ped_exception_catch(); + case PED_EXCEPTION_CANCEL: + free(diobuf); + return (0); + } + } + + free(diobuf); + + return (1); +} + +static int +solaris_write(PedDevice* dev, const void* buffer, PedSector start, + PedSector count) +{ + SolarisSpecific* arch_specific; + int status; + PedExceptionOption ex_status; + size_t write_length = count * dev->sector_size; + char *diobuf; + char *diobuf_start; + + PED_ASSERT(dev != NULL, return (0)); + PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return (0)); + PED_ASSERT(dev->open_count > 0, return (0)); + PED_ASSERT(!dev->external_mode, return (0)); + + arch_specific = SOLARIS_SPECIFIC(dev); + + 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 (_device_seek(dev, start)) + 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("solaris_write(\"%s\", %p, %d, %d)\n", + dev->path, buffer, (int)start, (int)count); +#else + dev->dirty = 1; + + diobuf = memalign((size_t)PED_SECTOR_SIZE_DEFAULT, write_length); + if (diobuf == NULL) { + printf("solaris_write: cannot memalign %u\n", write_length); + return (0); + } + + memcpy(diobuf, buffer, write_length); + diobuf_start = diobuf; + while (1) { + status = write(arch_specific->fd, diobuf, write_length); + if (status == write_length) + break; + if (status > 0) { + printf("solaris_write: partial write %d of %d\n", + status, write_length); + write_length -= status; + diobuf += 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: + free(diobuf_start); + return (1); + + case PED_EXCEPTION_RETRY: + break; + + case PED_EXCEPTION_UNHANDLED: + ped_exception_catch(); + case PED_EXCEPTION_CANCEL: + free(diobuf_start); + return (0); + } + } + free(diobuf_start); +#endif /* !READ_ONLY */ + + return (1); +} + + +/* + * returns the number of sectors that are ok. + * This is never called. It would get called through ped_device_check(). + */ +static PedSector +solaris_check(PedDevice* dev, void* buffer, PedSector start, PedSector count) +{ + SolarisSpecific* arch_specific; + PedSector done; + int status; + void* diobuf; + + PED_ASSERT(dev != NULL, return (0LL)); + PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, + return (0LL)); + PED_ASSERT(dev->open_count > 0, return (0LL)); + PED_ASSERT(!dev->external_mode, return (0LL)); + + printf("solaris_check: start %lld count %lld\n", start, count); + + arch_specific = SOLARIS_SPECIFIC(dev); + + if (!_device_seek(dev, start)) + return (0LL); + + diobuf = memalign(PED_SECTOR_SIZE_DEFAULT, count * dev->sector_size); + if (diobuf == NULL) { + printf("solaris_check: cannot memalign %u\n", + count * dev->sector_size); + return (0LL); + } + + for (done = 0; done < count; done += status / dev->sector_size) { + status = read(arch_specific->fd, diobuf, + (size_t)((count - done) * dev->sector_size)); + if (status < 0) + break; + } + free(diobuf); + + return (done); +} + +static int +solaris_sync(PedDevice* dev) +{ + PED_ASSERT(dev != NULL, return (0)); + PED_ASSERT(!dev->external_mode, return (0)); + + if (dev->read_only) + return (1); + if (!_do_fsync(dev)) + return (0); + return (1); +} + +/* + * Returns all *p0 block devices. + * open the raw device so ioctl works. + */ +static void +solaris_probe_all() +{ + DIR *dir; + struct dirent *dp; + char *pname; + char block_path[256]; + char raw_path[256]; + struct stat buffer; + int fd; + + dir = opendir("/dev/dsk"); + while ((dp = readdir(dir)) != NULL) { + + pname = dp->d_name + strlen(dp->d_name) - 2; + if (strcmp(pname, "p0") == 0) { + + strncpy(block_path, "/dev/dsk/", sizeof (block_path)); + strncat(block_path, dp->d_name, sizeof (block_path) - 1); + + strncpy(raw_path, "/dev/rdsk/", sizeof (raw_path)); + strncat(raw_path, dp->d_name, sizeof (raw_path) - 1); + + if (stat(block_path, &buffer) == 0) { + + if ((fd = open(raw_path, O_RDONLY)) < 0) { + continue; + } + +#ifdef DONT_ALLOW_REMOVEABLE_DEVICES + int n = 0; + if (ioctl(fd, DKIOCREMOVABLE, &n) < 0) { + char msg[MAXPATHLEN]; + snprintf(msg, sizeof (msg), + "ioctl(\"%s\", DKIOCREMOVABLE)", + raw_path); + perror(msg); + } else if (!n) { + /* + * Not a removable device + * printf("solaris_probe_all: %s\n", + * block_path); + */ + } +#endif /* DONT_ALLOW_REMOVEABLE_DEVICES */ + + _ped_device_probe(block_path); + close(fd); + } + } + } +} + +static char * +solaris_partition_get_path(const PedPartition* part) +{ + return (_device_get_part_path(part->disk->dev, part->num)); +} + +/* + * Returns 1 if the partition is busy in some way, 0 otherwise. + */ +static int +solaris_partition_is_busy(const PedPartition* part) +{ + int r1, r2, r3; + + PED_ASSERT(part != NULL, return (0)); + + r1 = checkmount(part->geom.dev, part->geom.start, part->geom.end); + r2 = checkswap(part->geom.dev, part->geom.start, part->geom.end); + r3 = checkdevinuse(part->geom.dev, part->geom.start, part->geom.end, 1); + + if (r1 || r2 || r3) + return (1); + + return (0); +} + +static int +solaris_disk_commit(PedDisk* disk) +{ + return (1); +} + +static PedDeviceArchOps solaris_dev_ops = { + ._new = solaris_new, + .destroy = solaris_destroy, + .is_busy = solaris_is_busy, + .open = solaris_open, + .refresh_open = solaris_refresh_open, + .close = solaris_close, + .refresh_close = solaris_refresh_close, + .read = solaris_read, + .write = solaris_write, + .check = solaris_check, + .sync = solaris_sync, + .sync_fast = solaris_sync, + .probe_all = solaris_probe_all +}; + +PedDiskArchOps solaris_disk_ops = { + .partition_get_path = solaris_partition_get_path, + .partition_is_busy = solaris_partition_is_busy, + .disk_commit = solaris_disk_commit +}; + +PedArchitecture ped_solaris_arch = { + .dev_ops = &solaris_dev_ops, + .disk_ops = &solaris_disk_ops +}; --- parted-1.8.8/libparted/libparted.c.orig +++ parted-1.8.8/libparted/libparted.c @@ -26,6 +26,8 @@ # include <parted/linux.h> #elif defined(__BEOS__) # include <parted/beos.h> +#elif defined(__sun) +# include <parted/solaris.h> #else # include <parted/gnu.h> #endif @@ -195,6 +197,8 @@ ped_set_architecture (&ped_linux_arch); #elif defined(__BEOS__) ped_set_architecture (&ped_beos_arch); +#elif defined (__sun) + ped_set_architecture (&ped_solaris_arch); #else ped_set_architecture (&ped_gnu_arch); #endif --- parted-1.8.8/libparted/Makefile.in.orig +++ parted-1.8.8/libparted/Makefile.in @@ -424,6 +424,7 @@ EXTRA_libparted_la_SOURCES = arch/linux.c \ arch/gnu.c \ + arch/solaris.c \ arch/beos.c libparted_la_LIBADD = $(OS_LIBS) \ @@ -508,6 +509,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/$(OS).Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/beos.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/solaris.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/constraint.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/device.Plo@am__quote@ @@ -592,6 +594,13 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o beos.lo `test -f 'arch/beos.c' || echo '$(srcdir)/'`arch/beos.c +solaris.lo: arch/solaris.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT solaris.lo -MD -MP -MF $(DEPDIR)/solaris.Tpo -c -o solaris.lo `test -f 'arch/solaris.c' || echo '$(srcdir)/'`arch/solaris.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/solaris.Tpo $(DEPDIR)/solaris.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='arch/solaris.c' object='solaris.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o solaris.lo `test -f 'arch/solaris.c' || echo '$(srcdir)/'`arch/solaris.c + mostlyclean-libtool: -rm -f *.lo --- /dev/null +++ parted-1.8.8/include/parted/solaris.h @@ -0,0 +1,42 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef PED_SOLARIS_H_INCLUDED +#define PED_SOLARIS_H_INCLUDED + +#include <parted/parted.h> + +#define SOLARIS_SPECIFIC(dev) ((SolarisSpecific*) (dev)->arch_specific) + +typedef struct _SolarisSpecific SolarisSpecific; + +struct _SolarisSpecific { + int fd; +}; + +extern PedArchitecture ped_solaris_arch; + +#endif /* PED_SOLARIS_H_INCLUDED */ --- parted-1.8.8/include/parted/Makefile.in.orig +++ parted-1.8.8/include/parted/Makefile.in @@ -83,7 +83,7 @@ DIST_SOURCES = am__partedinclude_HEADERS_DIST = gnu.h linux.h constraint.h debug.h \ device.h disk.h exception.h filesys.h geom.h natmath.h timer.h \ - unit.h parted.h fdasd.h vtoc.h + unit.h parted.h fdasd.h vtoc.h solaris.h am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ @@ -381,6 +381,7 @@ timer.h \ unit.h \ parted.h \ + solaris.h \ $(S390_HDRS) noinst_HEADERS = crc32.h \