Exemplo n.º 1
0
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
}
Exemplo n.º 2
0
/*
 * readefi(): Read a partition map.
 */
static int
readefi(int fd, char *name, struct dk_gpt **efi)
{
    int	retval;

    if ((retval = efi_alloc_and_read(fd, efi)) >= 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);
}
Exemplo n.º 3
0
/*
 * returns NULL if the slice is good (e.g. does not start at block
 * zero, or a string describing the error if it doesn't
 */
static boolean_t
is_good_slice(char *sfile, char **err)
{
	int fd, rc;
	struct vtoc vtoc;
	dk_gpt_t *gpt;
	char rdskname[MAXPATHLEN];
	char *x, *y;

	*err = NULL;
	/* convert from dsk to rdsk */
	STRCPYLIM(rdskname, sfile, "disk name");
	x = strstr(rdskname, "dsk/");
	y = strstr(sfile, "dsk/");
	if (x != NULL) {
		*x++ = 'r';
		(void) strcpy(x, y);
	}

	if ((fd = open(rdskname, O_RDONLY)) == -1) {
		*err = "could not open '%s'\n";
	} else if ((rc = read_vtoc(fd, &vtoc)) >= 0) {
		/*
		 * we got a slice number; now check the block
		 * number where the slice starts
		 */
		if (vtoc.v_part[rc].p_start < 2)
			*err = "using '%s' would clobber the disk label\n";
		(void) close(fd);
		return (*err ? B_FALSE : B_TRUE);
	} else if ((rc == VT_ENOTSUP) &&
	    (efi_alloc_and_read(fd, &gpt)) >= 0) {
		/* EFI slices don't clobber the disk label */
		free(gpt);
		(void) close(fd);
		return (B_TRUE);
	} else
		*err = "could not read partition table from '%s'\n";
	return (B_FALSE);
}
Exemplo n.º 4
0
static void
partinfo(int fd, char *device)
{
	int i;
	int	slice;
	major_t maj;
	minor_t min;
	struct stat64 statbuf;
	struct vtoc vtdata;
	struct dk_gpt *efi;

	i = stat64(device, &statbuf);
	if (i < 0)
		exit(DRERR);
	maj = major(statbuf.st_rdev);
	min = minor(statbuf.st_rdev);

	if ((slice = readvtoc(fd, device, &vtdata)) >= 0) {

		(void) printf("%s\t%0lx\t%0lx\t%ld\t%ld\t%x\t%x\n",
			device, maj, min,
			vtdata.v_part[slice].p_start,
			vtdata.v_part[slice].p_size,
			vtdata.v_part[slice].p_flag,
			vtdata.v_part[slice].p_tag);
	} else if ((slice == VT_ENOTSUP) &&
	    (slice = efi_alloc_and_read(fd, &efi)) >= 0) {
		(void) printf("%s\t%lx\t%lx\t%lld\t%lld\t%hx\t%hx\n",
			device, maj, min,
			efi->efi_parts[slice].p_start,
			efi->efi_parts[slice].p_size,
			efi->efi_parts[slice].p_flag,
			efi->efi_parts[slice].p_tag);
	} else {
		exit(DRERR);
	}
}
Exemplo n.º 5
0
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 vtoc vtoc;
	dk_gpt_t *gpt;
	struct dk_minfo mi;
	int i, dos_cnt;
	fstyp_handle_t fstyp_handle;
	int systid, relsect, numsect;
	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(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, &relsect, &numsect, &systid)) {
			goto out;
		}
		partition_scheme = "mbr";
		partition_start = (dbus_uint64_t)relsect * 512;
		partition_number = dos_num;
		probe_offset = (off_t)relsect * 512;
	} else {
		if ((partition_number = read_vtoc(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;

}
Exemplo n.º 6
0
static int
get_start_sector(ig_device_t *device)
{
	uint32_t		secnum = 0, numsec = 0;
	int			i, pno, rval, log_part = 0;
	struct mboot		*mboot;
	struct ipart		*part;
	ext_part_t		*epp;
	struct part_info	dkpi;
	struct extpart_info	edkpi;

	if (is_efi(device->type)) {
		struct dk_gpt *vtoc;

		if (efi_alloc_and_read(device->disk_fd, &vtoc) < 0)
			return (BC_ERROR);

		device->start_sector = vtoc->efi_parts[device->slice].p_start;
		/* GPT doesn't use traditional slice letters */
		device->slice = 0xff;
		device->partition = 0;

		efi_free(vtoc);
		goto found_part;
	}

	mboot = (struct mboot *)device->boot_sector;

	if (is_bootpar(device->type)) {
		if (find_x86_bootpar(mboot, &pno, &secnum) != BC_SUCCESS) {
			(void) fprintf(stderr, NOBOOTPAR);
			return (BC_ERROR);
		} else {
			device->start_sector = secnum;
			device->partition = pno;
			goto found_part;
		}
	}

	/*
	 * Search for Solaris fdisk partition
	 * Get the solaris partition information from the device
	 * and compare the offset of S2 with offset of solaris partition
	 * from fdisk partition table.
	 */
	if (ioctl(device->part_fd, DKIOCEXTPARTINFO, &edkpi) < 0) {
		if (ioctl(device->part_fd, DKIOCPARTINFO, &dkpi) < 0) {
			(void) fprintf(stderr, PART_FAIL);
			return (BC_ERROR);
		} else {
			edkpi.p_start = dkpi.p_start;
		}
	}

	for (i = 0; i < FD_NUMPART; i++) {
		part = (struct ipart *)mboot->parts + i;

		if (part->relsect == 0) {
			(void) fprintf(stderr, BAD_PART, i);
			return (BC_ERROR);
		}

		if (edkpi.p_start >= part->relsect &&
		    edkpi.p_start < (part->relsect + part->numsect)) {
			/* Found the partition */
			break;
		}
	}

	if (i == FD_NUMPART) {
		/* No solaris fdisk partitions (primary or logical) */
		(void) fprintf(stderr, NOSOLPAR);
		return (BC_ERROR);
	}

	/*
	 * We have found a Solaris fdisk partition (primary or extended)
	 * Handle the simple case first: Solaris in a primary partition
	 */
	if (!fdisk_is_dos_extended(part->systid)) {
		device->start_sector = part->relsect;
		device->partition = i;
		goto found_part;
	}

	/*
	 * Solaris in a logical partition. Find that partition in the
	 * extended part.
	 */
	if ((rval = libfdisk_init(&epp, device->path_p0, NULL, FDISK_READ_DISK))
	    != FDISK_SUCCESS) {
		switch (rval) {
			/*
			 * The first 3 cases are not an error per-se, just that
			 * there is no Solaris logical partition
			 */
			case FDISK_EBADLOGDRIVE:
			case FDISK_ENOLOGDRIVE:
			case FDISK_EBADMAGIC:
				(void) fprintf(stderr, NOSOLPAR);
				return (BC_ERROR);
			case FDISK_ENOVGEOM:
				(void) fprintf(stderr, NO_VIRT_GEOM);
				return (BC_ERROR);
			case FDISK_ENOPGEOM:
				(void) fprintf(stderr, NO_PHYS_GEOM);
				return (BC_ERROR);
			case FDISK_ENOLGEOM:
				(void) fprintf(stderr, NO_LABEL_GEOM);
				return (BC_ERROR);
			default:
				(void) fprintf(stderr, LIBFDISK_INIT_FAIL);
				return (BC_ERROR);
		}
	}

	rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
	libfdisk_fini(&epp);
	if (rval != FDISK_SUCCESS) {
		/* No solaris logical partition */
		(void) fprintf(stderr, NOSOLPAR);
		return (BC_ERROR);
	}

	device->start_sector = secnum;
	device->partition = pno - 1;
	log_part = 1;

found_part:
	/* get confirmation for -m */
	if (write_mbr && !force_mbr) {
		(void) fprintf(stdout, MBOOT_PROMPT);
		if (!yes()) {
			write_mbr = 0;
			(void) fprintf(stdout, MBOOT_NOT_UPDATED);
			return (BC_ERROR);
		}
	}

	/*
	 * Currently if Solaris is in an extended partition we need to
	 * write GRUB to the MBR. Check for this.
	 */
	if (log_part && !write_mbr) {
		(void) fprintf(stdout, gettext("Installing Solaris on an "
		    "extended partition... forcing MBR update\n"));
		write_mbr = 1;
	}

	/*
	 * warn, if Solaris in primary partition and GRUB not in MBR and
	 * partition is not active
	 */
	if (!log_part && part->bootid != 128 && !write_mbr) {
		(void) fprintf(stdout, SOLPAR_INACTIVE, device->partition + 1);
	}

	return (BC_SUCCESS);
}
Exemplo n.º 7
0
/*
 * open the device and fill the various members of ig_device_t.
 */
static int
init_device(ig_device_t *device, char *path)
{
	struct dk_gpt *vtoc;
	fstyp_handle_t fhdl;
	const char *fident;

	bzero(device, sizeof (*device));
	device->part_fd = -1;
	device->disk_fd = -1;
	device->path_p0 = NULL;

	device->path = strdup(path);
	if (device->path == NULL) {
		perror(gettext("Memory allocation failed"));
		return (BC_ERROR);
	}

	if (strstr(device->path, "diskette")) {
		(void) fprintf(stderr, gettext("installing GRUB to a floppy "
		    "disk is no longer supported\n"));
		return (BC_ERROR);
	}

	/* Detect if the target device is a pcfs partition. */
	if (strstr(device->path, "p0:boot"))
		device->type = IG_DEV_X86BOOTPAR;

	if (get_disk_fd(device) != BC_SUCCESS)
		return (BC_ERROR);

	/* read in the device boot sector. */
	if (read(device->disk_fd, device->boot_sector, SECTOR_SIZE)
	    != SECTOR_SIZE) {
		(void) fprintf(stderr, gettext("Error reading boot sector\n"));
		perror("read");
		return (BC_ERROR);
	}

	if (efi_alloc_and_read(device->disk_fd, &vtoc) >= 0) {
		device->type = IG_DEV_EFI;
		efi_free(vtoc);
	}

	if (get_raw_partition_fd(device) != BC_SUCCESS)
		return (BC_ERROR);

	if (is_efi(device->type)) {
		if (fstyp_init(device->part_fd, 0, NULL, &fhdl) != 0)
			return (BC_ERROR);

		if (fstyp_ident(fhdl, "zfs", &fident) != 0) {
			fstyp_fini(fhdl);
			(void) fprintf(stderr, gettext("Booting of EFI labeled "
			    "disks is only supported with ZFS\n"));
			return (BC_ERROR);
		}
		fstyp_fini(fhdl);
	}

	if (get_start_sector(device) != BC_SUCCESS)
		return (BC_ERROR);

	return (BC_SUCCESS);
}
Exemplo n.º 8
0
/*
 * 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);
}
Exemplo n.º 9
0
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);
}
Exemplo n.º 10
0
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);
}
Exemplo n.º 11
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);
}