1N/A/***************************************************************************
1N/A *
1N/A * probe-volume.c : probe volumes
1N/A *
1N/A * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
1N/A *
1N/A * Licensed under the Academic Free License version 2.1
1N/A *
1N/A **************************************************************************/
1N/A
1N/A#ifdef HAVE_CONFIG_H
1N/A# include <config.h>
1N/A#endif
1N/A
1N/A#include <errno.h>
1N/A#include <string.h>
1N/A#include <stdlib.h>
1N/A#include <stdio.h>
1N/A#include <sys/ioctl.h>
1N/A#include <sys/types.h>
1N/A#include <sys/stat.h>
1N/A#include <fcntl.h>
1N/A#include <unistd.h>
1N/A#include <ctype.h>
1N/A#include <time.h>
1N/A#include <sys/time.h>
1N/A#include <sys/dkio.h>
1N/A#include <sys/cdio.h>
1N/A#include <libnvpair.h>
1N/A#include <libfstyp.h>
1N/A#include <sys/vtoc.h>
1N/A#include <sys/efi_partition.h>
1N/A#include <sys/fs/hsfs_spec.h>
1N/A#include <sys/fs/hsfs_isospec.h>
1N/A#include <priv.h>
1N/A#include <sys/u8_textprep.h>
1N/A
1N/A#include <libhal.h>
1N/A#include <cdutils.h>
1N/A#include <fsutils.h>
1N/A#include <logger.h>
1N/A
1N/Astatic void
1N/Amy_dbus_error_free(DBusError *error)
1N/A{
1N/A if (dbus_error_is_set(error)) {
1N/A dbus_error_free(error);
1N/A }
1N/A}
1N/A
1N/A/*
1N/A * Return a copy of a string without trailing spaces. If 'len' is non-zero,
1N/A * it specifies max length, otherwise the string must be null-terminated.
1N/A */
1N/Astatic char *
1N/Artrim_copy(char *src, int len)
1N/A{
1N/A char *dst, *p;
1N/A
1N/A if (len == 0) {
1N/A len = strlen(src);
1N/A }
1N/A if ((dst = calloc(1, len + 1)) != NULL) {
1N/A strncpy(dst, src, len);
1N/A p = dst + len - 1;
1N/A while ((p >= dst) && (isspace(*p))) {
1N/A *p-- = '\0';
1N/A }
1N/A }
1N/A return (dst);
1N/A}
1N/A
1N/Astatic void
1N/Aset_fstyp_properties (LibHalContext *ctx, const char *udi, const char *fstype, nvlist_t *fsattr)
1N/A{
1N/A char buf[256];
1N/A DBusError error;
1N/A char *uuid = NULL;
1N/A char *label_orig = NULL;
1N/A char *label = NULL;
1N/A int err;
1N/A LibHalChangeSet *cs;
1N/A
1N/A dbus_error_init (&error);
1N/A
1N/A if ((cs = libhal_device_new_changeset (udi)) == NULL) {
1N/A return;
1N/A }
1N/A
1N/A libhal_changeset_set_property_string (cs, "volume.fsusage", "filesystem");
1N/A libhal_changeset_set_property_string (cs, "volume.fstype", fstype);
1N/A
1N/A /* label */
1N/A (void) nvlist_lookup_string(fsattr, "gen_volume_label", &label_orig);
1N/A if (label_orig != NULL) {
1N/A label = rtrim_copy(label_orig, 0);
1N/A }
1N/A /* Check if label is utf8 format */
1N/A if ((label != NULL) && (label[0] != '\0') &&
1N/A (u8_validate(label, strlen(label), (char **)NULL,
1N/A U8_VALIDATE_ENTIRE, &err) != -1)) {
1N/A libhal_changeset_set_property_string (cs, "volume.label", label);
1N/A libhal_changeset_set_property_string (cs, "info.product", label);
1N/A } else {
1N/A libhal_changeset_set_property_string (cs, "volume.label", "");
1N/A snprintf (buf, sizeof (buf), "Volume (%s)", fstype);
1N/A libhal_changeset_set_property_string (cs, "info.product", buf);
1N/A }
1N/A free(label);
1N/A
1N/A /* uuid */
1N/A if (nvlist_lookup_string(fsattr, "gen_uuid", &uuid) == 0) {
1N/A libhal_changeset_set_property_string (cs, "volume.uuid", uuid);
1N/A } else {
1N/A libhal_changeset_set_property_string (cs, "volume.uuid", "");
1N/A }
1N/A
1N/A libhal_device_commit_changeset (ctx, cs, &error);
1N/A libhal_device_free_changeset (cs);
1N/A
1N/A my_dbus_error_free (&error);
1N/A}
1N/A
1N/A/*
1N/A * hsfs/iso9660 contents detection: Video DVD, Video CD, etc.
1N/A */
1N/Astatic void
1N/Ahsfs_contents(int fd, off_t probe_offset, LibHalContext *ctx, const char *udi)
1N/A{
1N/A size_t secsz = ISO_SECTOR_SIZE;
1N/A uchar_t buf[ISO_SECTOR_SIZE];
1N/A int ptbl_lbn, ptbl_size;
1N/A int off, reloff, readoff;
1N/A uchar_t *p;
1N/A char *name;
1N/A int name_len;
1N/A int ipe_len;
1N/A DBusError error;
1N/A
1N/A /*
1N/A * find 1st Primary Volume Descriptor
1N/A */
1N/A readoff = probe_offset + ISO_VOLDESC_SEC * secsz;
1N/A if (pread (fd, buf, secsz, readoff) != secsz) {
1N/A return;
1N/A }
1N/A while (ISO_DESC_TYPE (buf) != ISO_VD_PVD) {
1N/A if (ISO_DESC_TYPE (buf) == ISO_VD_EOV) {
1N/A return;
1N/A }
1N/A readoff += secsz;
1N/A if (pread (fd, buf, secsz, readoff) != secsz) {
1N/A return;
1N/A }
1N/A }
1N/A
1N/A /*
1N/A * PVD contains size and offset of the LSB/MSB path table
1N/A */
1N/A ptbl_size = ISO_PTBL_SIZE (buf);
1N/A#if defined(_LITTLE_ENDIAN)
1N/A ptbl_lbn = ISO_PTBL_MAN_LS (buf);
1N/A#else
1N/A ptbl_lbn = ISO_PTBL_MAN_MS (buf);
1N/A#endif
1N/A
1N/A /*
1N/A * Look through path table entries
1N/A */
1N/A readoff = probe_offset + ptbl_lbn * secsz;
1N/A if (pread (fd, buf, secsz, readoff) != secsz) {
1N/A return;
1N/A }
1N/A dbus_error_init (&error);
1N/A
1N/A for (off = reloff = 0;
1N/A off < ptbl_size;
1N/A off += ipe_len, reloff += ipe_len) {
1N/A
1N/A /* load sectors on demand */
1N/A if (reloff >= secsz) {
1N/A readoff += secsz;
1N/A if (pread (fd, buf, secsz, readoff) != secsz) {
1N/A break;
1N/A }
1N/A reloff -= secsz;
1N/A }
1N/A
1N/A p = buf + reloff;
1N/A name_len = IPE_NAME_LEN(p);
1N/A ipe_len = IPE_FPESIZE + name_len + (name_len % 2);
1N/A
1N/A /* only interested in root directories */
1N/A if (IPE_PARENT_NO (p) != 1) {
1N/A continue;
1N/A }
1N/A if ((name_len < 2) || (name_len > IDE_MAX_NAME_LEN)) {
1N/A continue;
1N/A }
1N/A
1N/A name = (char *)IPE_NAME (p);
1N/A if (strncasecmp (name, "VIDEO_TS", min (8, name_len)) == 0) {
1N/A libhal_device_set_property_bool (ctx, udi,
1N/A "volume.disc.is_videodvd", TRUE, &error);
1N/A } else if (strncasecmp (name, "VCD", min (3, name_len)) == 0) {
1N/A libhal_device_set_property_bool (ctx, udi,
1N/A "volume.disc.is_vcd", TRUE, &error);
1N/A } else if (strncasecmp (name, "SVCD", min (4, name_len)) == 0) {
1N/A libhal_device_set_property_bool (ctx, udi,
1N/A "volume.disc.is_svcd", TRUE, &error);
1N/A }
1N/A }
1N/A
1N/A my_dbus_error_free (&error);
1N/A}
1N/A
1N/Astatic dbus_bool_t
1N/Aprobe_disc (int fd, LibHalContext *ctx, const char *udi, dbus_bool_t *has_data,
1N/A dbus_bool_t *has_audio)
1N/A{
1N/A DBusError error;
1N/A disc_info_t di;
1N/A int profile;
1N/A dbus_bool_t is_blank, is_appendable, is_rewritable;
1N/A char *disc_type = "cd_rom";
1N/A uint64_t capacity = 0;
1N/A int i;
1N/A LibHalChangeSet *cs;
1N/A
1N/A dbus_error_init (&error);
1N/A
1N/A if (get_disc_info (fd, &di)) {
1N/A is_blank = (di.disc_status == 0);
1N/A is_appendable = (di.disc_status == 1);
1N/A is_rewritable = (di.erasable != 0);
1N/A } else {
1N/A is_blank = is_appendable = is_rewritable = FALSE;
1N/A }
1N/A
1N/A if (get_current_profile (fd, &profile)) {
1N/A switch (profile) {
1N/A case 0x08: /* CD-ROM */
1N/A disc_type = "cd_rom";
1N/A break;
1N/A case 0x09: /* CD-R */
1N/A disc_type = "cd_r";
1N/A break;
1N/A case 0x0A: /* CD-RW */
1N/A disc_type = "cd_rw";
1N/A is_rewritable = TRUE;
1N/A break;
1N/A case 0x10: /* DVD-ROM */
1N/A disc_type = "dvd_rom";
1N/A break;
1N/A case 0x11: /* DVD-R Sequential */
1N/A disc_type = "dvd_r";
1N/A break;
1N/A case 0x12: /* DVD-RAM */
1N/A disc_type = "dvd_ram";
1N/A is_rewritable = TRUE;
1N/A break;
1N/A case 0x13: /* DVD-RW Restricted Overwrite */
1N/A disc_type = "dvd_rw";
1N/A is_rewritable = TRUE;
1N/A break;
1N/A case 0x14: /* DVD-RW Sequential */
1N/A disc_type = "dvd_rw";
1N/A is_rewritable = TRUE;
1N/A break;
1N/A case 0x1A: /* DVD+RW */
1N/A disc_type = "dvd_plus_rw";
1N/A is_rewritable = TRUE;
1N/A break;
1N/A case 0x1B: /* DVD+R */
1N/A disc_type = "dvd_plus_r";
1N/A break;
1N/A case 0x2B: /* DVD+R Double Layer */
1N/A disc_type = "dvd_plus_r_dl";
1N/A break;
1N/A case 0x40: /* BD-ROM */
1N/A disc_type = "bd_rom";
1N/A break;
1N/A case 0x41: /* BD-R Sequential */
1N/A disc_type = "bd_r";
1N/A break;
1N/A case 0x42: /* BD-R Random */
1N/A disc_type = "bd_r";
1N/A break;
1N/A case 0x43: /* BD-RE */
1N/A disc_type = "bd_re";
1N/A is_rewritable = TRUE;
1N/A break;
1N/A case 0x50: /* HD DVD-ROM */
1N/A disc_type = "hddvd_rom";
1N/A break;
1N/A case 0x51: /* HD DVD-R */
1N/A disc_type = "hddvd_r";
1N/A break;
1N/A case 0x52: /* HD DVD-Rewritable */
1N/A disc_type = "hddvd_rw";
1N/A is_rewritable = TRUE;
1N/A break;
1N/A }
1N/A
1N/A (void) get_disc_capacity_for_profile(fd, profile, &capacity);
1N/A }
1N/A
1N/A *has_audio = *has_data = FALSE;
1N/A if (!is_blank) {
1N/A uchar_t smalltoc[12];
1N/A size_t toc_size;
1N/A uchar_t *toc, *p;
1N/A
1N/A /*
1N/A * XXX for some reason CDROMREADTOCENTRY fails on video DVDs,
1N/A * but extracting the toc directly works okay. And the toc
1N/A * data buffer length passed to read_toc() should be the same
1N/A * as the real buffer size.
1N/A */
1N/A if (!read_toc(fd, 0, 1, 12, smalltoc)) {
1N/A HAL_DEBUG(("read_toc failed"));
1N/A *has_data = B_TRUE; /* probe for fs anyway */
1N/A } else {
1N/A toc_size = smalltoc[0] * 256 + smalltoc[1] + 2;
1N/A toc = (uchar_t *)calloc(1, toc_size);
1N/A if (toc == NULL || !read_toc(fd, 0, 1, toc_size, toc)) {
1N/A HAL_DEBUG (("read_toc again failed"));
1N/A } else {
1N/A for (p = &toc[4]; p < (toc + toc_size); p += 8) {
1N/A /* skip leadout */
1N/A if (p[2] == 0xAA) {
1N/A continue;
1N/A }
1N/A if (p[1] & 4) {
1N/A *has_data = B_TRUE;
1N/A } else {
1N/A *has_audio = B_TRUE;
1N/A }
1N/A }
1N/A }
1N/A free(toc);
1N/A }
1N/A }
1N/A
1N/A if ((cs = libhal_device_new_changeset (udi)) == NULL) {
1N/A return (FALSE);
1N/A }
1N/A libhal_changeset_set_property_string (cs, "volume.disc.type", disc_type);
1N/A libhal_changeset_set_property_bool (cs, "volume.disc.is_blank", is_blank);
1N/A libhal_changeset_set_property_bool (cs, "volume.disc.has_audio", *has_audio);
1N/A libhal_changeset_set_property_bool (cs, "volume.disc.has_data", *has_data);
1N/A libhal_changeset_set_property_bool (cs, "volume.disc.is_appendable", is_appendable);
1N/A libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", is_rewritable);
1N/A libhal_changeset_set_property_uint64 (cs, "volume.disc.capacity", capacity);
1N/A
1N/A libhal_changeset_set_property_bool (cs, "volume.disc.is_videodvd", FALSE);
1N/A libhal_changeset_set_property_bool (cs, "volume.disc.is_vcd", FALSE);
1N/A libhal_changeset_set_property_bool (cs, "volume.disc.is_svcd", FALSE);
1N/A
1N/A libhal_device_commit_changeset (ctx, cs, &error);
1N/A libhal_device_free_changeset (cs);
1N/A
1N/Aout:
1N/A my_dbus_error_free (&error);
1N/A
1N/A return (TRUE);
1N/A}
1N/A
1N/Astatic void
1N/Adrop_privileges ()
1N/A{
1N/A priv_set_t *pPrivSet = NULL;
1N/A priv_set_t *lPrivSet = NULL;
1N/A
1N/A /*
1N/A * Start with the 'basic' privilege set and then remove any
1N/A * of the 'basic' privileges that will not be needed.
1N/A */
1N/A if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) {
1N/A return;
1N/A }
1N/A
1N/A /* Clear privileges we will not need from the 'basic' set */
1N/A (void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
1N/A (void) priv_delset(pPrivSet, PRIV_PROC_INFO);
1N/A (void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
1N/A (void) priv_delset(pPrivSet, PRIV_PROC_EXEC);
1N/A (void) priv_delset(pPrivSet, PRIV_PROC_FORK);
1N/A
1N/A /* for uscsi */
1N/A (void) priv_addset(pPrivSet, PRIV_SYS_DEVICES);
1N/A
1N/A
1N/A /* to open logindevperm'd devices */
1N/A (void) priv_addset(pPrivSet, PRIV_FILE_DAC_READ);
1N/A
1N/A /* Set the permitted privilege set. */
1N/A if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
1N/A return;
1N/A }
1N/A
1N/A /* Clear the limit set. */
1N/A if ((lPrivSet = priv_allocset()) == NULL) {
1N/A return;
1N/A }
1N/A
1N/A priv_emptyset(lPrivSet);
1N/A
1N/A if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) {
1N/A return;
1N/A }
1N/A
1N/A priv_freeset(lPrivSet);
1N/A}
1N/A
1N/Aint
1N/Amain (int argc, char *argv[])
1N/A{
1N/A int fd, rfd;
1N/A int ret;
1N/A char *udi;
1N/A char *device_file, *raw_device_file;
1N/A char *devpath, *rdevpath;
1N/A boolean_t is_dos;
1N/A int dos_num;
1N/A LibHalContext *ctx = NULL;
1N/A DBusError error;
1N/A DBusConnection *conn;
1N/A char *parent_udi;
1N/A char *storage_device;
1N/A char *is_disc_str;
1N/A dbus_bool_t is_disc = FALSE;
1N/A unsigned int block_size;
1N/A dbus_uint64_t vol_size;
1N/A dbus_bool_t has_data = TRUE; /* probe for fs by default */
1N/A dbus_bool_t has_audio = FALSE;
1N/A char *partition_scheme = NULL;
1N/A dbus_uint64_t partition_start = 0;
1N/A int partition_number = 0;
1N/A struct extvtoc vtoc;
1N/A dk_gpt_t *gpt;
1N/A struct dk_minfo mi;
1N/A int i, dos_cnt;
1N/A fstyp_handle_t fstyp_handle;
1N/A off_t probe_offset = 0;
1N/A int num_volumes;
1N/A char **volumes;
1N/A dbus_uint64_t v_start;
1N/A const char *fstype;
1N/A nvlist_t *fsattr;
1N/A
1N/A fd = rfd = -1;
1N/A
1N/A ret = 1;
1N/A
1N/A if ((udi = getenv ("UDI")) == NULL) {
1N/A goto out;
1N/A }
1N/A if ((device_file = getenv ("HAL_PROP_BLOCK_DEVICE")) == NULL) {
1N/A goto out;
1N/A }
1N/A if ((raw_device_file = getenv ("HAL_PROP_BLOCK_SOLARIS_RAW_DEVICE")) == NULL) {
1N/A goto out;
1N/A }
1N/A if (!dos_to_dev(raw_device_file, &rdevpath, &dos_num)) {
1N/A rdevpath = raw_device_file;
1N/A }
1N/A if (!(is_dos = dos_to_dev(device_file, &devpath, &dos_num))) {
1N/A devpath = device_file;
1N/A }
1N/A if ((parent_udi = getenv ("HAL_PROP_INFO_PARENT")) == NULL) {
1N/A goto out;
1N/A }
1N/A if ((storage_device = getenv ("HAL_PROP_BLOCK_STORAGE_DEVICE")) == NULL) {
1N/A goto out;
1N/A }
1N/A
1N/A is_disc_str = getenv ("HAL_PROP_VOLUME_IS_DISC");
1N/A if (is_disc_str != NULL && strcmp (is_disc_str, "true") == 0) {
1N/A is_disc = TRUE;
1N/A } else {
1N/A is_disc = FALSE;
1N/A }
1N/A
1N/A drop_privileges ();
1N/A
1N/A setup_logger ();
1N/A
1N/A dbus_error_init (&error);
1N/A if ((ctx = libhal_ctx_init_direct (&error)) == NULL)
1N/A goto out;
1N/A
1N/A HAL_DEBUG (("Doing probe-volume for %s\n", device_file));
1N/A
1N/A fd = open (devpath, O_RDONLY | O_NONBLOCK);
1N/A if (fd < 0) {
1N/A goto out;
1N/A }
1N/A rfd = open (rdevpath, O_RDONLY | O_NONBLOCK);
1N/A if (rfd < 0) {
1N/A goto out;
1N/A }
1N/A
1N/A /* block size and total size */
1N/A if (ioctl(rfd, DKIOCGMEDIAINFO, &mi) != -1) {
1N/A block_size = mi.dki_lbsize;
1N/A vol_size = mi.dki_capacity * block_size;
1N/A } else if (errno == ENXIO) {
1N/A /* driver supports ioctl, but media is not available */
1N/A goto out;
1N/A } else {
1N/A /* driver does not support ioctl, e.g. lofi */
1N/A block_size = 512;
1N/A vol_size = 0;
1N/A }
1N/A libhal_device_set_property_int (ctx, udi, "volume.block_size", block_size, &error);
1N/A my_dbus_error_free (&error);
1N/A libhal_device_set_property_uint64 (ctx, udi, "volume.size", vol_size, &error);
1N/A my_dbus_error_free (&error);
1N/A
1N/A if (is_disc) {
1N/A if (!probe_disc (rfd, ctx, udi, &has_data, &has_audio)) {
1N/A HAL_DEBUG (("probe_disc failed, skipping fstyp"));
1N/A goto out;
1N/A }
1N/A /* with audio present, create volume even if fs probing fails */
1N/A if (has_audio) {
1N/A ret = 0;
1N/A }
1N/A }
1N/A
1N/A if (!has_data) {
1N/A goto skip_fs;
1N/A }
1N/A
1N/A /*
1N/A * first get partitioning info
1N/A */
1N/A if (is_dos) {
1N/A /* for a dos drive find partition offset */
1N/A if (!find_dos_drive(fd, dos_num, block_size, &probe_offset)) {
1N/A goto out;
1N/A }
1N/A partition_scheme = "mbr";
1N/A partition_start = (dbus_uint64_t)probe_offset;
1N/A partition_number = dos_num;
1N/A } else {
1N/A if ((partition_number = read_extvtoc(rfd, &vtoc)) >= 0) {
1N/A if (!vtoc_one_slice_entire_disk(&vtoc)) {
1N/A partition_scheme = "smi";
1N/A if (partition_number < vtoc.v_nparts) {
1N/A if (vtoc.v_part[partition_number].p_size == 0) {
1N/A HAL_DEBUG (("zero size partition"));
1N/A }
1N/A partition_start = vtoc.v_part[partition_number].p_start * block_size;
1N/A }
1N/A }
1N/A } else if ((partition_number = efi_alloc_and_read(rfd, &gpt)) >= 0) {
1N/A partition_scheme = "gpt";
1N/A if (partition_number < gpt->efi_nparts) {
1N/A if (gpt->efi_parts[partition_number].p_size == 0) {
1N/A HAL_DEBUG (("zero size partition"));
1N/A }
1N/A partition_start = gpt->efi_parts[partition_number].p_start * block_size;
1N/A }
1N/A efi_free(gpt);
1N/A }
1N/A probe_offset = 0;
1N/A }
1N/A
1N/A if (partition_scheme != NULL) {
1N/A libhal_device_set_property_string (ctx, udi, "volume.partition.scheme", partition_scheme, &error);
1N/A my_dbus_error_free (&error);
1N/A libhal_device_set_property_int (ctx, udi, "volume.partition.number", partition_number, &error);
1N/A my_dbus_error_free (&error);
1N/A libhal_device_set_property_uint64 (ctx, udi, "volume.partition.start", partition_start, &error);
1N/A my_dbus_error_free (&error);
1N/A libhal_device_set_property_bool (ctx, udi, "volume.is_partition", TRUE, &error);
1N/A my_dbus_error_free (&error);
1N/A } else {
1N/A libhal_device_set_property_bool (ctx, udi, "volume.is_partition", FALSE, &error);
1N/A my_dbus_error_free (&error);
1N/A }
1N/A
1N/A /*
1N/A * ignore duplicate partitions
1N/A */
1N/A if ((volumes = libhal_manager_find_device_string_match (
1N/A ctx, "block.storage_device", storage_device, &num_volumes, &error)) != NULL) {
1N/A my_dbus_error_free (&error);
1N/A for (i = 0; i < num_volumes; i++) {
1N/A if (strcmp (udi, volumes[i]) == 0) {
1N/A continue; /* skip self */
1N/A }
1N/A v_start = libhal_device_get_property_uint64 (ctx, volumes[i], "volume.partition.start", &error);
1N/A if (dbus_error_is_set(&error)) {
1N/A dbus_error_free(&error);
1N/A continue;
1N/A }
1N/A if (v_start == partition_start) {
1N/A HAL_DEBUG (("duplicate partition"));
1N/A goto out;
1N/A }
1N/A }
1N/A libhal_free_string_array (volumes);
1N/A }
1N/A
1N/Askip_part:
1N/A
1N/A /*
1N/A * now determine fs type
1N/A *
1N/A * XXX We could get better performance from block device,
1N/A * but for now we use raw device because:
1N/A *
1N/A * - fstyp_udfs has a bug that it only works on raw
1N/A *
1N/A * - sd has a bug that causes extremely slow reads
1N/A * and incorrect probing of hybrid audio/data media
1N/A */
1N/A if (fstyp_init(rfd, probe_offset, NULL, &fstyp_handle) != 0) {
1N/A HAL_DEBUG (("fstyp_init failed"));
1N/A goto out;
1N/A }
1N/A if ((fstyp_ident(fstyp_handle, NULL, &fstype) != 0) ||
1N/A (fstyp_get_attr(fstyp_handle, &fsattr) != 0)) {
1N/A HAL_DEBUG (("fstyp ident or get_attr failed"));
1N/A fstyp_fini(fstyp_handle);
1N/A goto out;
1N/A }
1N/A set_fstyp_properties (ctx, udi, fstype, fsattr);
1N/A
1N/A if (strcmp (fstype, "hsfs") == 0) {
1N/A hsfs_contents (fd, probe_offset, ctx, udi);
1N/A }
1N/A
1N/A fstyp_fini(fstyp_handle);
1N/A
1N/Askip_fs:
1N/A
1N/A ret = 0;
1N/A
1N/Aout:
1N/A if (fd >= 0)
1N/A close (fd);
1N/A if (rfd >= 0)
1N/A close (rfd);
1N/A
1N/A if (ctx != NULL) {
1N/A my_dbus_error_free (&error);
1N/A libhal_ctx_shutdown (ctx, &error);
1N/A libhal_ctx_free (ctx);
1N/A }
1N/A
1N/A return ret;
1N/A
1N/A}