static void check_slices(avl_tree_t *r, int fd, const char *sname) { #ifdef sun struct extvtoc vtoc; struct dk_gpt *gpt; char diskname[MAXNAMELEN]; char *ptr; int i; (void) strncpy(diskname, sname, MAXNAMELEN); if ((ptr = strrchr(diskname, 's')) == NULL || !isdigit(ptr[1])) return; ptr[1] = '\0'; if (read_extvtoc(fd, &vtoc) >= 0) { for (i = 0; i < NDKMAP; i++) check_one_slice(r, diskname, i, vtoc.v_part[i].p_size, vtoc.v_sectorsz); } else if (efi_alloc_and_read(fd, &gpt) >= 0) { /* * on x86 we'll still have leftover links that point * to slices s[9-15], so use NDKMAP instead */ for (i = 0; i < NDKMAP; i++) check_one_slice(r, diskname, i, gpt->efi_parts[i].p_size, gpt->efi_lbasize); /* nodes p[1-4] are never used with EFI labels */ ptr[0] = 'p'; for (i = 1; i <= FD_NUMPART; i++) check_one_slice(r, diskname, i, 0, 1); efi_free(gpt); } #endif }
/* * readvtoc(): Read a partition map. */ static int readvtoc(int fd, char *name, struct extvtoc *vtoc) { int retval; if ((retval = read_extvtoc(fd, vtoc)) >= 0) return (0); switch (retval) { case (VT_EIO): return (warn(name, "Unable to read VTOC")); case (VT_EINVAL): return (warn(name, "Invalid VTOC")); case (VT_ERROR): return (warn(name, "Unknown problem reading VTOC")); } return (retval); }
int main (int argc, char *argv[]) { int fd, rfd; int ret; char *udi; char *device_file, *raw_device_file; char *devpath, *rdevpath; boolean_t is_dos; int dos_num; LibHalContext *ctx = NULL; DBusError error; DBusConnection *conn; char *parent_udi; char *storage_device; char *is_disc_str; int fdc; dbus_bool_t is_disc = FALSE; dbus_bool_t is_floppy = FALSE; unsigned int block_size; dbus_uint64_t vol_size; dbus_bool_t has_data = TRUE; /* probe for fs by default */ dbus_bool_t has_audio = FALSE; char *partition_scheme = NULL; dbus_uint64_t partition_start = 0; int partition_number = 0; struct extvtoc vtoc; dk_gpt_t *gpt; struct dk_minfo mi; int i, dos_cnt; fstyp_handle_t fstyp_handle; off_t probe_offset = 0; int num_volumes; char **volumes; dbus_uint64_t v_start; const char *fstype; nvlist_t *fsattr; fd = rfd = -1; ret = 1; if ((udi = getenv ("UDI")) == NULL) { goto out; } if ((device_file = getenv ("HAL_PROP_BLOCK_DEVICE")) == NULL) { goto out; } if ((raw_device_file = getenv ("HAL_PROP_BLOCK_SOLARIS_RAW_DEVICE")) == NULL) { goto out; } if (!dos_to_dev(raw_device_file, &rdevpath, &dos_num)) { rdevpath = raw_device_file; } if (!(is_dos = dos_to_dev(device_file, &devpath, &dos_num))) { devpath = device_file; } if ((parent_udi = getenv ("HAL_PROP_INFO_PARENT")) == NULL) { goto out; } if ((storage_device = getenv ("HAL_PROP_BLOCK_STORAGE_DEVICE")) == NULL) { goto out; } is_disc_str = getenv ("HAL_PROP_VOLUME_IS_DISC"); if (is_disc_str != NULL && strcmp (is_disc_str, "true") == 0) { is_disc = TRUE; } else { is_disc = FALSE; } drop_privileges (); setup_logger (); dbus_error_init (&error); if ((ctx = libhal_ctx_init_direct (&error)) == NULL) goto out; HAL_DEBUG (("Doing probe-volume for %s\n", device_file)); fd = open (devpath, O_RDONLY | O_NONBLOCK); if (fd < 0) { goto out; } rfd = open (rdevpath, O_RDONLY | O_NONBLOCK); if (rfd < 0) { goto out; } /* if it's a floppy with no media, bail out */ if (ioctl(rfd, FDGETCHANGE, &fdc) == 0) { is_floppy = TRUE; if (fdc & FDGC_CURRENT) { goto out; } } /* block size and total size */ if (ioctl(rfd, DKIOCGMEDIAINFO, &mi) != -1) { block_size = mi.dki_lbsize; vol_size = mi.dki_capacity * block_size; } else if (errno == ENXIO) { /* driver supports ioctl, but media is not available */ goto out; } else { /* driver does not support ioctl, e.g. lofi */ block_size = 512; vol_size = 0; } libhal_device_set_property_int (ctx, udi, "volume.block_size", block_size, &error); my_dbus_error_free (&error); libhal_device_set_property_uint64 (ctx, udi, "volume.size", vol_size, &error); my_dbus_error_free (&error); if (is_disc) { if (!probe_disc (rfd, ctx, udi, &has_data, &has_audio)) { HAL_DEBUG (("probe_disc failed, skipping fstyp")); goto out; } /* with audio present, create volume even if fs probing fails */ if (has_audio) { ret = 0; } } if (!has_data) { goto skip_fs; } /* don't support partitioned floppy */ if (is_floppy) { goto skip_part; } /* * first get partitioning info */ if (is_dos) { /* for a dos drive find partition offset */ if (!find_dos_drive(fd, dos_num, block_size, &probe_offset)) { goto out; } partition_scheme = "mbr"; partition_start = (dbus_uint64_t)probe_offset; partition_number = dos_num; } else { if ((partition_number = read_extvtoc(rfd, &vtoc)) >= 0) { if (!vtoc_one_slice_entire_disk(&vtoc)) { partition_scheme = "smi"; if (partition_number < vtoc.v_nparts) { if (vtoc.v_part[partition_number].p_size == 0) { HAL_DEBUG (("zero size partition")); } partition_start = vtoc.v_part[partition_number].p_start * block_size; } } } else if ((partition_number = efi_alloc_and_read(rfd, &gpt)) >= 0) { partition_scheme = "gpt"; if (partition_number < gpt->efi_nparts) { if (gpt->efi_parts[partition_number].p_size == 0) { HAL_DEBUG (("zero size partition")); } partition_start = gpt->efi_parts[partition_number].p_start * block_size; } efi_free(gpt); } probe_offset = 0; } if (partition_scheme != NULL) { libhal_device_set_property_string (ctx, udi, "volume.partition.scheme", partition_scheme, &error); my_dbus_error_free (&error); libhal_device_set_property_int (ctx, udi, "volume.partition.number", partition_number, &error); my_dbus_error_free (&error); libhal_device_set_property_uint64 (ctx, udi, "volume.partition.start", partition_start, &error); my_dbus_error_free (&error); libhal_device_set_property_bool (ctx, udi, "volume.is_partition", TRUE, &error); my_dbus_error_free (&error); } else { libhal_device_set_property_bool (ctx, udi, "volume.is_partition", FALSE, &error); my_dbus_error_free (&error); } /* * ignore duplicate partitions */ if ((volumes = libhal_manager_find_device_string_match ( ctx, "block.storage_device", storage_device, &num_volumes, &error)) != NULL) { my_dbus_error_free (&error); for (i = 0; i < num_volumes; i++) { if (strcmp (udi, volumes[i]) == 0) { continue; /* skip self */ } v_start = libhal_device_get_property_uint64 (ctx, volumes[i], "volume.partition.start", &error); if (dbus_error_is_set(&error)) { dbus_error_free(&error); continue; } if (v_start == partition_start) { HAL_DEBUG (("duplicate partition")); goto out; } } libhal_free_string_array (volumes); } skip_part: /* * now determine fs type * * XXX We could get better performance from block device, * but for now we use raw device because: * * - fstyp_udfs has a bug that it only works on raw * * - sd has a bug that causes extremely slow reads * and incorrect probing of hybrid audio/data media */ if (fstyp_init(rfd, probe_offset, NULL, &fstyp_handle) != 0) { HAL_DEBUG (("fstyp_init failed")); goto out; } if ((fstyp_ident(fstyp_handle, NULL, &fstype) != 0) || (fstyp_get_attr(fstyp_handle, &fsattr) != 0)) { HAL_DEBUG (("fstyp ident or get_attr failed")); fstyp_fini(fstyp_handle); goto out; } set_fstyp_properties (ctx, udi, fstype, fsattr); if (strcmp (fstype, "hsfs") == 0) { hsfs_contents (fd, probe_offset, ctx, udi); } fstyp_fini(fstyp_handle); skip_fs: ret = 0; out: if (fd >= 0) close (fd); if (rfd >= 0) close (rfd); if (ctx != NULL) { my_dbus_error_free (&error); libhal_ctx_shutdown (ctx, &error); libhal_ctx_free (ctx); } return ret; }
/* * Just look for the name on the devpaths we have cached. Return 1 if we * find the name and the size of that slice is non-zero. */ static int match_fixed_name(disk_t *diskp, char *name, int *errp) { slice_t *dp = NULL; alias_t *ap; int slice_num; int fd; int status; int data_format = FMT_UNKNOWN; struct extvtoc vtoc; struct dk_gpt *efip; ap = diskp->aliases; while (ap != NULL) { slice_t *devp; devp = ap->devpaths; while (devp != NULL) { char path[MAXPATHLEN]; slice_rdsk2dsk(devp->devpath, path, sizeof (path)); if (libdiskmgt_str_eq(path, name)) { /* found it */ dp = devp; break; } devp = devp->next; } if (dp != NULL) { break; } ap = ap->next; } if (dp == NULL) { *errp = 0; return (0); } /* * If we found a match on the name we now have to check that this * slice really exists (non-0 size). */ slice_num = get_slice_num(dp); /* can't get slicenum, so no slice */ if (slice_num == -1) { *errp = ENODEV; return (1); } if ((fd = drive_open_disk(diskp, NULL, 0)) < 0) { *errp = ENODEV; return (1); } if ((status = read_extvtoc(fd, &vtoc)) >= 0) { data_format = FMT_VTOC; } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { data_format = FMT_EFI; } else { (void) close(fd); *errp = ENODEV; return (1); } (void) close(fd); if (data_format == FMT_VTOC) { if (slice_num < vtoc.v_nparts && vtoc.v_part[slice_num].p_size > 0) { *errp = 0; return (1); } } else { /* data_format == FMT_EFI */ if (slice_num < efip->efi_nparts && efip->efi_parts[slice_num].p_size > 0) { efi_free(efip); *errp = 0; return (1); } efi_free(efip); } *errp = ENODEV; return (1); }
static int make_fixed_descriptors(disk_t *dp) { int error = 0; alias_t *ap; slice_t *devp; char mname[MAXPATHLEN]; int data_format = FMT_UNKNOWN; struct extvtoc vtoc; struct dk_gpt *efip; /* Just check the first drive name. */ if ((ap = dp->aliases) == NULL) { return (0); } mname[0] = 0; (void) media_read_name(dp, mname, sizeof (mname)); for (devp = ap->devpaths; devp != NULL; devp = devp->next) { int slice_num; char devpath[MAXPATHLEN]; slice_num = get_slice_num(devp); /* can't get slicenum, so no need to keep trying the drive */ if (slice_num == -1) { break; } if (data_format == FMT_UNKNOWN) { int fd; int status; if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) { if ((status = read_extvtoc(fd, &vtoc)) >= 0) { data_format = FMT_VTOC; } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { data_format = FMT_EFI; } (void) close(fd); } } /* can't get slice data, so no need to keep trying the drive */ if (data_format == FMT_UNKNOWN) { break; } if (data_format == FMT_VTOC) { if (slice_num >= vtoc.v_nparts || vtoc.v_part[slice_num].p_size == 0) { continue; } } else { /* data_format == FMT_EFI */ if (slice_num >= efip->efi_nparts || efip->efi_parts[slice_num].p_size == 0) { continue; } } slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath)); cache_load_desc(DM_SLICE, dp, devpath, mname, &error); if (error != 0) { break; } } if (data_format == FMT_EFI) { efi_free(efip); } return (error); }
static int get_attrs(descriptor_t *dp, int fd, nvlist_t *attrs) { struct dk_minfo minfo; int status; int data_format = FMT_UNKNOWN; int snum = -1; int error; struct extvtoc vtoc; struct dk_gpt *efip; struct dk_cinfo dkinfo; int cooked_fd; struct stat buf; if (fd < 0) { return (ENODEV); } /* First make sure media is inserted and spun up. */ if (!media_read_info(fd, &minfo)) { return (ENODEV); } if ((status = read_extvtoc(fd, &vtoc)) >= 0) { data_format = FMT_VTOC; } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { data_format = FMT_EFI; if (nvlist_add_boolean(attrs, DM_EFI) != 0) { efi_free(efip); return (ENOMEM); } } if (data_format == FMT_UNKNOWN) { return (ENODEV); } if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) { snum = dkinfo.dki_partition; } /* check the slice */ if (data_format == FMT_VTOC) { if (snum < 0 || snum >= vtoc.v_nparts || vtoc.v_part[snum].p_size == 0) { return (ENODEV); } } else { /* data_format == FMT_EFI */ if (snum < 0 || snum >= efip->efi_nparts || efip->efi_parts[snum].p_size == 0) { efi_free(efip); return (ENODEV); } } /* the slice exists */ if (nvlist_add_uint32(attrs, DM_INDEX, snum) != 0) { if (data_format == FMT_EFI) { efi_free(efip); } return (ENOMEM); } if (data_format == FMT_VTOC) { if (nvlist_add_uint64(attrs, DM_START, vtoc.v_part[snum].p_start) != 0) { return (ENOMEM); } if (nvlist_add_uint64(attrs, DM_SIZE, vtoc.v_part[snum].p_size) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_TAG, vtoc.v_part[snum].p_tag) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_FLAG, vtoc.v_part[snum].p_flag) != 0) { return (ENOMEM); } } else { /* data_format == FMT_EFI */ if (nvlist_add_uint64(attrs, DM_START, efip->efi_parts[snum].p_start) != 0) { efi_free(efip); return (ENOMEM); } if (nvlist_add_uint64(attrs, DM_SIZE, efip->efi_parts[snum].p_size) != 0) { efi_free(efip); return (ENOMEM); } if (efip->efi_parts[snum].p_name[0] != 0) { char label[EFI_PART_NAME_LEN + 1]; (void) snprintf(label, sizeof (label), "%.*s", EFI_PART_NAME_LEN, efip->efi_parts[snum].p_name); if (nvlist_add_string(attrs, DM_EFI_NAME, label) != 0) { efi_free(efip); return (ENOMEM); } } } if (data_format == FMT_EFI) { efi_free(efip); } if (inuse_mnt(dp->name, attrs, &error)) { if (error != 0) return (error); } if (fstat(fd, &buf) != -1) { if (nvlist_add_uint64(attrs, DM_DEVT, buf.st_rdev) != 0) { return (ENOMEM); } } /* * We need to open the cooked slice (not the raw one) to get the * correct devid. */ cooked_fd = open(dp->name, O_RDONLY|O_NDELAY); if (cooked_fd >= 0) { int no_mem = 0; ddi_devid_t devid; if (devid_get(cooked_fd, &devid) == 0) { char *minor; if (devid_get_minor_name(cooked_fd, &minor) == 0) { char *devidstr; if ((devidstr = devid_str_encode(devid, minor)) != 0) { if (nvlist_add_string(attrs, DM_DEVICEID, devidstr) != 0) { no_mem = 1; } devid_str_free(devidstr); } devid_str_free(minor); } devid_free(devid); } (void) close(cooked_fd); if (no_mem) { return (ENOMEM); } } return (0); }
static int get_attrs(disk_t *dp, int fd, nvlist_t *attrs) { struct dk_minfo minfo; struct dk_geom geometry; if (fd < 0) { return (ENODEV); } bzero(&minfo, sizeof (struct dk_minfo)); /* The first thing to do is read the media */ if (!media_read_info(fd, &minfo)) { return (ENODEV); } if (partition_has_fdisk(dp, fd)) { if (nvlist_add_boolean(attrs, DM_FDISK) != 0) { return (ENOMEM); } } if (dp->removable) { if (nvlist_add_boolean(attrs, DM_REMOVABLE) != 0) { return (ENOMEM); } if (nvlist_add_boolean(attrs, DM_LOADED) != 0) { return (ENOMEM); } } if (nvlist_add_uint64(attrs, DM_SIZE, minfo.dki_capacity) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_BLOCKSIZE, minfo.dki_lbsize) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_MTYPE, get_media_type(minfo.dki_media_type)) != 0) { return (ENOMEM); } /* only for disks < 1TB and x86 */ #if defined(i386) || defined(__amd64) if (ioctl(fd, DKIOCG_PHYGEOM, &geometry) >= 0) { #else /* sparc call */ if (ioctl(fd, DKIOCGGEOM, &geometry) >= 0) { #endif struct extvtoc vtoc; if (nvlist_add_uint64(attrs, DM_START, 0) != 0) { return (ENOMEM); } if (nvlist_add_uint64(attrs, DM_NACCESSIBLE, geometry.dkg_ncyl * geometry.dkg_nhead * geometry.dkg_nsect) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_NCYLINDERS, geometry.dkg_ncyl) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_NPHYSCYLINDERS, geometry.dkg_pcyl) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_NALTCYLINDERS, geometry.dkg_acyl) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_NHEADS, geometry.dkg_nhead) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_NSECTORS, geometry.dkg_nsect) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_NACTUALCYLINDERS, geometry.dkg_ncyl) != 0) { return (ENOMEM); } if (read_extvtoc(fd, &vtoc) >= 0 && vtoc.v_volume[0] != 0) { char label[LEN_DKL_VVOL + 1]; (void) snprintf(label, sizeof (label), "%.*s", LEN_DKL_VVOL, vtoc.v_volume); if (nvlist_add_string(attrs, DM_LABEL, label) != 0) { return (ENOMEM); } } } else { /* check for disks > 1TB for accessible size */ struct dk_gpt *efip; if (efi_alloc_and_read(fd, &efip) >= 0) { diskaddr_t p8size = 0; if (nvlist_add_boolean(attrs, DM_EFI) != 0) { return (ENOMEM); } if (nvlist_add_uint64(attrs, DM_START, efip->efi_first_u_lba) != 0) { return (ENOMEM); } /* partition 8 is reserved on EFI labels */ if (efip->efi_nparts >= 9) { p8size = efip->efi_parts[8].p_size; } if (nvlist_add_uint64(attrs, DM_NACCESSIBLE, (efip->efi_last_u_lba - p8size) - efip->efi_first_u_lba) != 0) { efi_free(efip); return (ENOMEM); } efi_free(efip); } } return (0); } static int get_media_type(uint_t media_type) { switch (media_type) { case DK_UNKNOWN: return (DM_MT_UNKNOWN); case DK_MO_ERASABLE: return (DM_MT_MO_ERASABLE); case DK_MO_WRITEONCE: return (DM_MT_MO_WRITEONCE); case DK_AS_MO: return (DM_MT_AS_MO); case DK_CDROM: return (DM_MT_CDROM); case DK_CDR: return (DM_MT_CDR); case DK_CDRW: return (DM_MT_CDRW); case DK_DVDROM: return (DM_MT_DVDROM); case DK_DVDR: return (DM_MT_DVDR); case DK_DVDRAM: return (DM_MT_DVDRAM); case DK_FIXED_DISK: return (DM_MT_FIXED); case DK_FLOPPY: return (DM_MT_FLOPPY); case DK_ZIP: return (DM_MT_ZIP); case DK_JAZ: return (DM_MT_JAZ); default: return (DM_MT_UNKNOWN); } } /* * This function handles removable media. */ static int get_rmm_name(disk_t *dp, char *mname, int size) { int loaded; int fd; loaded = 0; if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) { struct dk_minfo minfo; if ((loaded = media_read_info(fd, &minfo))) { struct extvtoc vtoc; if (read_extvtoc(fd, &vtoc) >= 0) { if (vtoc.v_volume[0] != NULL) { if (LEN_DKL_VVOL < size) { (void) strlcpy(mname, vtoc.v_volume, LEN_DKL_VVOL); } else { (void) strlcpy(mname, vtoc.v_volume, size); } } } } (void) close(fd); } return (loaded); }