xref: /titanic_52/usr/src/cmd/hal/probing/volume/probe-volume.c (revision 0ae7db0fea6d3b73d011439fac4224a03a42db52)
118c2aff7Sartem /***************************************************************************
218c2aff7Sartem  *
318c2aff7Sartem  * probe-volume.c : probe volumes
418c2aff7Sartem  *
5*0ae7db0fSfei feng - Sun Microsystems - Beijing China  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
618c2aff7Sartem  *
718c2aff7Sartem  * Licensed under the Academic Free License version 2.1
818c2aff7Sartem  *
918c2aff7Sartem  **************************************************************************/
1018c2aff7Sartem 
1118c2aff7Sartem #ifdef HAVE_CONFIG_H
1218c2aff7Sartem #  include <config.h>
1318c2aff7Sartem #endif
1418c2aff7Sartem 
1518c2aff7Sartem #include <errno.h>
1618c2aff7Sartem #include <string.h>
1718c2aff7Sartem #include <stdlib.h>
1818c2aff7Sartem #include <stdio.h>
1918c2aff7Sartem #include <sys/ioctl.h>
2018c2aff7Sartem #include <sys/types.h>
2118c2aff7Sartem #include <sys/stat.h>
2218c2aff7Sartem #include <fcntl.h>
2318c2aff7Sartem #include <unistd.h>
2418c2aff7Sartem #include <ctype.h>
2518c2aff7Sartem #include <time.h>
2618c2aff7Sartem #include <sys/time.h>
2718c2aff7Sartem #include <sys/dkio.h>
2818c2aff7Sartem #include <sys/cdio.h>
2918c2aff7Sartem #include <sys/fdio.h>
3018c2aff7Sartem #include <libnvpair.h>
3118c2aff7Sartem #include <libfstyp.h>
3218c2aff7Sartem #include <sys/vtoc.h>
3318c2aff7Sartem #include <sys/efi_partition.h>
347544909dSartem #include <sys/fs/hsfs_spec.h>
357544909dSartem #include <sys/fs/hsfs_isospec.h>
3618c2aff7Sartem #include <priv.h>
37de7d23d8SLin Guo - Sun Microsystems #include <sys/u8_textprep.h>
3818c2aff7Sartem 
3918c2aff7Sartem #include <libhal.h>
4018c2aff7Sartem #include <cdutils.h>
4118c2aff7Sartem #include <fsutils.h>
4218c2aff7Sartem #include <logger.h>
4318c2aff7Sartem 
4418c2aff7Sartem static void
4518c2aff7Sartem my_dbus_error_free(DBusError *error)
4618c2aff7Sartem {
4718c2aff7Sartem 	if (dbus_error_is_set(error)) {
4818c2aff7Sartem 		dbus_error_free(error);
4918c2aff7Sartem 	}
5018c2aff7Sartem }
5118c2aff7Sartem 
5218c2aff7Sartem /*
5318c2aff7Sartem  * Return a copy of a string without trailing spaces. If 'len' is non-zero,
5418c2aff7Sartem  * it specifies max length, otherwise the string must be null-terminated.
5518c2aff7Sartem  */
5618c2aff7Sartem static char *
5718c2aff7Sartem rtrim_copy(char *src, int len)
5818c2aff7Sartem {
5918c2aff7Sartem 	char	*dst, *p;
6018c2aff7Sartem 
6118c2aff7Sartem 	if (len == 0) {
6218c2aff7Sartem 		len = strlen(src);
6318c2aff7Sartem 	}
6418c2aff7Sartem 	if ((dst = calloc(1, len + 1)) != NULL) {
6518c2aff7Sartem 		strncpy(dst, src, len);
6618c2aff7Sartem 		p = dst + len - 1;
6718c2aff7Sartem 		while ((p >= dst) && (isspace(*p))) {
6818c2aff7Sartem 			*p-- = '\0';
6918c2aff7Sartem 		}
7018c2aff7Sartem 	}
7118c2aff7Sartem 	return (dst);
7218c2aff7Sartem }
7318c2aff7Sartem 
7418c2aff7Sartem static void
7518c2aff7Sartem set_fstyp_properties (LibHalContext *ctx, const char *udi, const char *fstype, nvlist_t *fsattr)
7618c2aff7Sartem {
7718c2aff7Sartem 	char buf[256];
7818c2aff7Sartem 	DBusError error;
7918c2aff7Sartem 	char *uuid = NULL;
8018c2aff7Sartem 	char *label_orig = NULL;
8118c2aff7Sartem 	char *label = NULL;
82de7d23d8SLin Guo - Sun Microsystems 	int  err;
8318c2aff7Sartem 	LibHalChangeSet *cs;
8418c2aff7Sartem 
8518c2aff7Sartem 	dbus_error_init (&error);
8618c2aff7Sartem 
8718c2aff7Sartem 	if ((cs = libhal_device_new_changeset (udi)) == NULL) {
8818c2aff7Sartem 		return;
8918c2aff7Sartem 	}
9018c2aff7Sartem 
9118c2aff7Sartem 	libhal_changeset_set_property_string (cs, "volume.fsusage", "filesystem");
9218c2aff7Sartem 	libhal_changeset_set_property_string (cs, "volume.fstype", fstype);
9318c2aff7Sartem 
9418c2aff7Sartem 	/* label */
9518c2aff7Sartem 	(void) nvlist_lookup_string(fsattr, "gen_volume_label", &label_orig);
9618c2aff7Sartem 	if (label_orig != NULL) {
9718c2aff7Sartem 		label = rtrim_copy(label_orig, 0);
9818c2aff7Sartem 	}
99de7d23d8SLin Guo - Sun Microsystems 	/* Check if label is utf8 format */
100de7d23d8SLin Guo - Sun Microsystems 	if ((label != NULL) && (label[0] != '\0') &&
101de7d23d8SLin Guo - Sun Microsystems 	    (u8_validate(label, strlen(label), (char **)NULL,
102de7d23d8SLin Guo - Sun Microsystems 	    U8_VALIDATE_ENTIRE, &err) != -1)) {
10318c2aff7Sartem 	        libhal_changeset_set_property_string (cs, "volume.label", label);
10418c2aff7Sartem 	        libhal_changeset_set_property_string (cs, "info.product", label);
10518c2aff7Sartem 	} else {
10618c2aff7Sartem 		libhal_changeset_set_property_string (cs, "volume.label", "");
10718c2aff7Sartem 		snprintf (buf, sizeof (buf), "Volume (%s)", fstype);
10818c2aff7Sartem 		libhal_changeset_set_property_string (cs, "info.product", buf);
10918c2aff7Sartem 	}
11018c2aff7Sartem 	free(label);
11118c2aff7Sartem 
11218c2aff7Sartem 	/* uuid */
11318c2aff7Sartem 	if (nvlist_lookup_string(fsattr, "gen_uuid", &uuid) == 0) {
11418c2aff7Sartem 		libhal_changeset_set_property_string (cs, "volume.uuid", uuid);
11518c2aff7Sartem 	} else {
11618c2aff7Sartem 		libhal_changeset_set_property_string (cs, "volume.uuid", "");
11718c2aff7Sartem 	}
11818c2aff7Sartem 
11918c2aff7Sartem 	libhal_device_commit_changeset (ctx, cs, &error);
12018c2aff7Sartem 	libhal_device_free_changeset (cs);
12118c2aff7Sartem 
12218c2aff7Sartem 	my_dbus_error_free (&error);
12318c2aff7Sartem }
12418c2aff7Sartem 
1257544909dSartem /*
1267544909dSartem  * hsfs/iso9660 contents detection: Video DVD, Video CD, etc.
1277544909dSartem  */
1287544909dSartem static void
1297544909dSartem hsfs_contents(int fd, off_t probe_offset, LibHalContext *ctx, const char *udi)
1307544909dSartem {
1317544909dSartem 	size_t	secsz = ISO_SECTOR_SIZE;
1327544909dSartem 	uchar_t	buf[ISO_SECTOR_SIZE];
1337544909dSartem 	int	ptbl_lbn, ptbl_size;
1347544909dSartem 	int	off, reloff, readoff;
1357544909dSartem 	uchar_t	*p;
1367544909dSartem 	char	*name;
1377544909dSartem 	int	name_len;
1387544909dSartem 	int	ipe_len;
1397544909dSartem 	DBusError error;
1407544909dSartem 
1417544909dSartem 	/*
1427544909dSartem 	 * find 1st Primary Volume Descriptor
1437544909dSartem 	 */
1447544909dSartem 	readoff = probe_offset + ISO_VOLDESC_SEC * secsz;
1457544909dSartem 	if (pread (fd, buf, secsz, readoff) != secsz) {
1467544909dSartem 		return;
1477544909dSartem 	}
1487544909dSartem 	while (ISO_DESC_TYPE (buf) != ISO_VD_PVD) {
1497544909dSartem 		if (ISO_DESC_TYPE (buf) == ISO_VD_EOV) {
1507544909dSartem 			return;
1517544909dSartem 		}
1527544909dSartem 		readoff += secsz;
1537544909dSartem 		if (pread (fd, buf, secsz, readoff) != secsz) {
1547544909dSartem 			return;
1557544909dSartem 		}
1567544909dSartem 	}
1577544909dSartem 
1587544909dSartem 	/*
1597544909dSartem 	 * PVD contains size and offset of the LSB/MSB path table
1607544909dSartem 	 */
1617544909dSartem 	ptbl_size = ISO_PTBL_SIZE (buf);
1627544909dSartem #if defined(_LITTLE_ENDIAN)
1637544909dSartem         ptbl_lbn = ISO_PTBL_MAN_LS (buf);
1647544909dSartem #else
1657544909dSartem         ptbl_lbn = ISO_PTBL_MAN_MS (buf);
1667544909dSartem #endif
1677544909dSartem 
1687544909dSartem 	/*
1697544909dSartem 	 * Look through path table entries
1707544909dSartem 	 */
1717544909dSartem 	readoff = probe_offset + ptbl_lbn * secsz;
1727544909dSartem 	if (pread (fd, buf, secsz, readoff) != secsz) {
1737544909dSartem 		return;
1747544909dSartem 	}
1757544909dSartem 	dbus_error_init (&error);
1767544909dSartem 
1777544909dSartem 	for (off = reloff = 0;
1787544909dSartem 	    off < ptbl_size;
1797544909dSartem 	    off += ipe_len, reloff += ipe_len) {
1807544909dSartem 
1817544909dSartem 		/* load sectors on demand */
1827544909dSartem 		if (reloff >= secsz) {
1837544909dSartem 			readoff += secsz;
1847544909dSartem 			if (pread (fd, buf, secsz, readoff) != secsz) {
1857544909dSartem 				break;
1867544909dSartem 			}
1877544909dSartem 			reloff -= secsz;
1887544909dSartem 		}
1897544909dSartem 
1907544909dSartem 		p = buf + reloff;
1917544909dSartem 		name_len = IPE_NAME_LEN(p);
1927544909dSartem 		ipe_len = IPE_FPESIZE + name_len + (name_len % 2);
1937544909dSartem 
1947544909dSartem 		/* only interested in root directories */
1957544909dSartem 		if (IPE_PARENT_NO (p) != 1) {
1967544909dSartem 			continue;
1977544909dSartem 		}
1987544909dSartem 		if ((name_len < 2) || (name_len > IDE_MAX_NAME_LEN)) {
1997544909dSartem 			continue;
2007544909dSartem 		}
2017544909dSartem 
2027544909dSartem 		name = (char *)IPE_NAME (p);
2037544909dSartem 		if (strncasecmp (name, "VIDEO_TS", min (8, name_len)) == 0) {
2047544909dSartem 			libhal_device_set_property_bool (ctx, udi,
2057544909dSartem 			    "volume.disc.is_videodvd", TRUE, &error);
2067544909dSartem 		} else if (strncasecmp (name, "VCD", min (3, name_len)) == 0) {
2077544909dSartem 			libhal_device_set_property_bool (ctx, udi,
2087544909dSartem 			    "volume.disc.is_vcd", TRUE, &error);
2097544909dSartem 		} else if (strncasecmp (name, "SVCD", min (4, name_len)) == 0) {
2107544909dSartem 			libhal_device_set_property_bool (ctx, udi,
2117544909dSartem 			    "volume.disc.is_svcd", TRUE, &error);
2127544909dSartem 		}
2137544909dSartem 	}
2147544909dSartem 
2157544909dSartem 	my_dbus_error_free (&error);
2167544909dSartem }
2177544909dSartem 
2187544909dSartem static dbus_bool_t
219b941d3fcSartem probe_disc (int fd, LibHalContext *ctx, const char *udi, dbus_bool_t *has_data,
220b941d3fcSartem     dbus_bool_t *has_audio)
22118c2aff7Sartem {
22218c2aff7Sartem 	DBusError error;
22318c2aff7Sartem 	disc_info_t di;
22418c2aff7Sartem 	int profile;
225b941d3fcSartem 	dbus_bool_t is_blank, is_appendable, is_rewritable;
22618c2aff7Sartem 	char *disc_type = "cd_rom";
22718c2aff7Sartem 	uint64_t capacity = 0;
22818c2aff7Sartem 	int i;
22918c2aff7Sartem 	LibHalChangeSet *cs;
23018c2aff7Sartem 
23118c2aff7Sartem 	dbus_error_init (&error);
23218c2aff7Sartem 
23318c2aff7Sartem 	if (get_disc_info (fd, &di)) {
23418c2aff7Sartem 		is_blank = (di.disc_status == 0);
23518c2aff7Sartem 		is_appendable = (di.disc_status == 1);
23618c2aff7Sartem 		is_rewritable = (di.erasable != 0);
23718c2aff7Sartem 	} else {
23818c2aff7Sartem 		is_blank = is_appendable = is_rewritable = FALSE;
23918c2aff7Sartem 	}
24018c2aff7Sartem 
24118c2aff7Sartem 	if (get_current_profile (fd, &profile)) {
24218c2aff7Sartem 		switch (profile) {
24318c2aff7Sartem 		case 0x08: /* CD-ROM */
24418c2aff7Sartem 			disc_type = "cd_rom";
24518c2aff7Sartem 			break;
24618c2aff7Sartem 		case 0x09: /* CD-R */
24718c2aff7Sartem 			disc_type = "cd_r";
24818c2aff7Sartem 			break;
24918c2aff7Sartem 		case 0x0A: /* CD-RW */
25018c2aff7Sartem 			disc_type = "cd_rw";
25118c2aff7Sartem 			is_rewritable = TRUE;
25218c2aff7Sartem 			break;
25318c2aff7Sartem 		case 0x10: /* DVD-ROM */
25418c2aff7Sartem 			disc_type = "dvd_rom";
25518c2aff7Sartem 			break;
25618c2aff7Sartem 		case 0x11: /* DVD-R Sequential */
25718c2aff7Sartem 			disc_type = "dvd_r";
25818c2aff7Sartem 			break;
25918c2aff7Sartem 		case 0x12: /* DVD-RAM */
26018c2aff7Sartem 			disc_type = "dvd_ram";
26118c2aff7Sartem 			is_rewritable = TRUE;
26218c2aff7Sartem 			break;
26318c2aff7Sartem 		case 0x13: /* DVD-RW Restricted Overwrite */
26418c2aff7Sartem 			disc_type = "dvd_rw";
26518c2aff7Sartem 			is_rewritable = TRUE;
26618c2aff7Sartem 			break;
26718c2aff7Sartem 		case 0x14: /* DVD-RW Sequential */
26818c2aff7Sartem 			disc_type = "dvd_rw";
26918c2aff7Sartem 			is_rewritable = TRUE;
27018c2aff7Sartem 			break;
27118c2aff7Sartem 		case 0x1A: /* DVD+RW */
27218c2aff7Sartem 			disc_type = "dvd_plus_rw";
27318c2aff7Sartem 			is_rewritable = TRUE;
27418c2aff7Sartem 			break;
27518c2aff7Sartem 		case 0x1B: /* DVD+R */
27618c2aff7Sartem 			disc_type = "dvd_plus_r";
27718c2aff7Sartem 			break;
27818c2aff7Sartem 		case 0x2B: /* DVD+R Double Layer */
27918c2aff7Sartem                         disc_type = "dvd_plus_r_dl";
28018c2aff7Sartem 			break;
28118c2aff7Sartem 		case 0x40: /* BD-ROM */
28218c2aff7Sartem                         disc_type = "bd_rom";
28318c2aff7Sartem 			break;
28418c2aff7Sartem 		case 0x41: /* BD-R Sequential */
28518c2aff7Sartem                         disc_type = "bd_r";
28618c2aff7Sartem 			break;
28718c2aff7Sartem 		case 0x42: /* BD-R Random */
28818c2aff7Sartem                         disc_type = "bd_r";
28918c2aff7Sartem 			break;
29018c2aff7Sartem 		case 0x43: /* BD-RE */
29118c2aff7Sartem                         disc_type = "bd_re";
29218c2aff7Sartem 			is_rewritable = TRUE;
29318c2aff7Sartem 			break;
29418c2aff7Sartem 		case 0x50: /* HD DVD-ROM */
29518c2aff7Sartem                         disc_type = "hddvd_rom";
29618c2aff7Sartem 			break;
29718c2aff7Sartem 		case 0x51: /* HD DVD-R */
29818c2aff7Sartem                         disc_type = "hddvd_r";
29918c2aff7Sartem 			break;
30018c2aff7Sartem 		case 0x52: /* HD DVD-Rewritable */
30118c2aff7Sartem                         disc_type = "hddvd_rw";
30218c2aff7Sartem 			is_rewritable = TRUE;
30318c2aff7Sartem 			break;
30418c2aff7Sartem 		}
30518c2aff7Sartem 
30618c2aff7Sartem 		(void) get_disc_capacity_for_profile(fd, profile, &capacity);
30718c2aff7Sartem 	}
30818c2aff7Sartem 
309b941d3fcSartem 	*has_audio = *has_data = FALSE;
31018c2aff7Sartem 	if (!is_blank) {
31118c2aff7Sartem 		uchar_t	smalltoc[12];
31218c2aff7Sartem 		size_t	toc_size;
31318c2aff7Sartem 		uchar_t	*toc, *p;
31418c2aff7Sartem 
31518c2aff7Sartem 		/*
31618c2aff7Sartem 		 * XXX for some reason CDROMREADTOCENTRY fails on video DVDs,
317*0ae7db0fSfei feng - Sun Microsystems - Beijing China 		 * but extracting the toc directly works okay. And the toc
318*0ae7db0fSfei feng - Sun Microsystems - Beijing China 		 * data buffer length passed to read_toc() should be the same
319*0ae7db0fSfei feng - Sun Microsystems - Beijing China 		 * as the real buffer size.
32018c2aff7Sartem 		 */
321*0ae7db0fSfei feng - Sun Microsystems - Beijing China 		if (!read_toc(fd, 0, 1, 12, smalltoc)) {
32218c2aff7Sartem                 	HAL_DEBUG(("read_toc failed"));
323b941d3fcSartem 			*has_data = B_TRUE; /* probe for fs anyway */
32418c2aff7Sartem         	} else {
32518c2aff7Sartem         		toc_size = smalltoc[0] * 256 + smalltoc[1] + 2;
32618c2aff7Sartem         		toc = (uchar_t *)calloc(1, toc_size);
32718c2aff7Sartem         		if (toc == NULL || !read_toc(fd, 0, 1, toc_size, toc)) {
32818c2aff7Sartem                 		HAL_DEBUG (("read_toc again failed"));
32918c2aff7Sartem         		} else {
33018c2aff7Sartem         			for (p = &toc[4]; p < (toc + toc_size); p += 8) {
33118c2aff7Sartem 					/* skip leadout */
33218c2aff7Sartem                 			if (p[2] == 0xAA) {
33318c2aff7Sartem 						continue;
33418c2aff7Sartem 					}
33518c2aff7Sartem 					if (p[1] & 4) {
336b941d3fcSartem 						*has_data = B_TRUE;
33718c2aff7Sartem 					} else {
338b941d3fcSartem 						*has_audio = B_TRUE;
33918c2aff7Sartem 					}
34018c2aff7Sartem         			}
34118c2aff7Sartem 			}
34218c2aff7Sartem 			free(toc);
34318c2aff7Sartem 		}
34418c2aff7Sartem 	}
34518c2aff7Sartem 
34618c2aff7Sartem 	if ((cs = libhal_device_new_changeset (udi)) == NULL) {
34718c2aff7Sartem 		return (FALSE);
34818c2aff7Sartem 	}
34918c2aff7Sartem 	libhal_changeset_set_property_string (cs, "volume.disc.type", disc_type);
35018c2aff7Sartem 	libhal_changeset_set_property_bool (cs, "volume.disc.is_blank", is_blank);
351b941d3fcSartem 	libhal_changeset_set_property_bool (cs, "volume.disc.has_audio", *has_audio);
352b941d3fcSartem 	libhal_changeset_set_property_bool (cs, "volume.disc.has_data", *has_data);
35318c2aff7Sartem 	libhal_changeset_set_property_bool (cs, "volume.disc.is_appendable", is_appendable);
35418c2aff7Sartem 	libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", is_rewritable);
35518c2aff7Sartem 	libhal_changeset_set_property_uint64 (cs, "volume.disc.capacity", capacity);
35618c2aff7Sartem 
3577544909dSartem 	libhal_changeset_set_property_bool (cs, "volume.disc.is_videodvd", FALSE);
3587544909dSartem 	libhal_changeset_set_property_bool (cs, "volume.disc.is_vcd", FALSE);
3597544909dSartem 	libhal_changeset_set_property_bool (cs, "volume.disc.is_svcd", FALSE);
3607544909dSartem 
36118c2aff7Sartem 	libhal_device_commit_changeset (ctx, cs, &error);
36218c2aff7Sartem 	libhal_device_free_changeset (cs);
36318c2aff7Sartem 
36418c2aff7Sartem out:
36518c2aff7Sartem 	my_dbus_error_free (&error);
36618c2aff7Sartem 
36718c2aff7Sartem 	return (TRUE);
36818c2aff7Sartem }
36918c2aff7Sartem 
3707544909dSartem static void
37118c2aff7Sartem drop_privileges ()
37218c2aff7Sartem {
37318c2aff7Sartem 	priv_set_t *pPrivSet = NULL;
37418c2aff7Sartem 	priv_set_t *lPrivSet = NULL;
37518c2aff7Sartem 
37618c2aff7Sartem 	/*
37718c2aff7Sartem 	 * Start with the 'basic' privilege set and then remove any
37818c2aff7Sartem 	 * of the 'basic' privileges that will not be needed.
37918c2aff7Sartem 	 */
38018c2aff7Sartem 	if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) {
38118c2aff7Sartem 		return;
38218c2aff7Sartem 	}
38318c2aff7Sartem 
38418c2aff7Sartem 	/* Clear privileges we will not need from the 'basic' set */
38518c2aff7Sartem 	(void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
38618c2aff7Sartem 	(void) priv_delset(pPrivSet, PRIV_PROC_INFO);
38718c2aff7Sartem 	(void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
38818c2aff7Sartem 	(void) priv_delset(pPrivSet, PRIV_PROC_EXEC);
38918c2aff7Sartem 	(void) priv_delset(pPrivSet, PRIV_PROC_FORK);
39018c2aff7Sartem 
39118c2aff7Sartem 	/* for uscsi */
39218c2aff7Sartem 	(void) priv_addset(pPrivSet, PRIV_SYS_DEVICES);
39318c2aff7Sartem 
39418c2aff7Sartem 
39518c2aff7Sartem 	/* to open logindevperm'd devices */
39618c2aff7Sartem 	(void) priv_addset(pPrivSet, PRIV_FILE_DAC_READ);
39718c2aff7Sartem 
39818c2aff7Sartem 	/* Set the permitted privilege set. */
39918c2aff7Sartem 	if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
40018c2aff7Sartem 		return;
40118c2aff7Sartem 	}
40218c2aff7Sartem 
40318c2aff7Sartem 	/* Clear the limit set. */
40418c2aff7Sartem 	if ((lPrivSet = priv_allocset()) == NULL) {
40518c2aff7Sartem 		return;
40618c2aff7Sartem 	}
40718c2aff7Sartem 
40818c2aff7Sartem 	priv_emptyset(lPrivSet);
40918c2aff7Sartem 
41018c2aff7Sartem 	if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) {
41118c2aff7Sartem 		return;
41218c2aff7Sartem 	}
41318c2aff7Sartem 
41418c2aff7Sartem 	priv_freeset(lPrivSet);
41518c2aff7Sartem }
41618c2aff7Sartem 
41718c2aff7Sartem int
41818c2aff7Sartem main (int argc, char *argv[])
41918c2aff7Sartem {
42018c2aff7Sartem 	int fd, rfd;
42118c2aff7Sartem 	int ret;
42218c2aff7Sartem 	char *udi;
42318c2aff7Sartem 	char *device_file, *raw_device_file;
42418c2aff7Sartem 	char *devpath, *rdevpath;
42518c2aff7Sartem 	boolean_t is_dos;
42618c2aff7Sartem 	int dos_num;
42718c2aff7Sartem 	LibHalContext *ctx = NULL;
42818c2aff7Sartem 	DBusError error;
42918c2aff7Sartem 	DBusConnection *conn;
43018c2aff7Sartem 	char *parent_udi;
43118c2aff7Sartem 	char *storage_device;
43218c2aff7Sartem 	char *is_disc_str;
43318c2aff7Sartem 	int fdc;
43418c2aff7Sartem 	dbus_bool_t is_disc = FALSE;
43518c2aff7Sartem 	dbus_bool_t is_floppy = FALSE;
43618c2aff7Sartem 	unsigned int block_size;
43718c2aff7Sartem 	dbus_uint64_t vol_size;
438b941d3fcSartem 	dbus_bool_t has_data = TRUE;	/* probe for fs by default */
439b941d3fcSartem 	dbus_bool_t has_audio = FALSE;
44018c2aff7Sartem 	char *partition_scheme = NULL;
44118c2aff7Sartem 	dbus_uint64_t partition_start = 0;
44289522cbbSartem 	int partition_number = 0;
443342440ecSPrasad Singamsetty 	struct extvtoc vtoc;
44418c2aff7Sartem 	dk_gpt_t *gpt;
44518c2aff7Sartem 	struct dk_minfo mi;
44618c2aff7Sartem 	int i, dos_cnt;
44718c2aff7Sartem 	fstyp_handle_t fstyp_handle;
44818c2aff7Sartem 	off_t probe_offset = 0;
44918c2aff7Sartem 	int num_volumes;
45018c2aff7Sartem 	char **volumes;
45118c2aff7Sartem 	dbus_uint64_t v_start;
45218c2aff7Sartem 	const char *fstype;
45318c2aff7Sartem 	nvlist_t *fsattr;
45418c2aff7Sartem 
45518c2aff7Sartem 	fd = rfd = -1;
45618c2aff7Sartem 
45718c2aff7Sartem 	ret = 1;
45818c2aff7Sartem 
45918c2aff7Sartem 	if ((udi = getenv ("UDI")) == NULL) {
46018c2aff7Sartem 		goto out;
46118c2aff7Sartem 	}
46218c2aff7Sartem 	if ((device_file = getenv ("HAL_PROP_BLOCK_DEVICE")) == NULL) {
46318c2aff7Sartem 		goto out;
46418c2aff7Sartem 	}
46518c2aff7Sartem 	if ((raw_device_file = getenv ("HAL_PROP_BLOCK_SOLARIS_RAW_DEVICE")) == NULL) {
46618c2aff7Sartem 		goto out;
46718c2aff7Sartem 	}
468422ee277Sartem 	if (!dos_to_dev(raw_device_file, &rdevpath, &dos_num)) {
46918c2aff7Sartem 		rdevpath = raw_device_file;
47018c2aff7Sartem 	}
47118c2aff7Sartem 	if (!(is_dos = dos_to_dev(device_file, &devpath, &dos_num))) {
47218c2aff7Sartem 		devpath = device_file;
47318c2aff7Sartem 	}
47418c2aff7Sartem 	if ((parent_udi = getenv ("HAL_PROP_INFO_PARENT")) == NULL) {
47518c2aff7Sartem 		goto out;
47618c2aff7Sartem 	}
47718c2aff7Sartem 	if ((storage_device = getenv ("HAL_PROP_BLOCK_STORAGE_DEVICE")) == NULL) {
47818c2aff7Sartem 		goto out;
47918c2aff7Sartem 	}
48018c2aff7Sartem 
48118c2aff7Sartem 	is_disc_str = getenv ("HAL_PROP_VOLUME_IS_DISC");
48218c2aff7Sartem 	if (is_disc_str != NULL && strcmp (is_disc_str, "true") == 0) {
48318c2aff7Sartem 		is_disc = TRUE;
48418c2aff7Sartem 	} else {
48518c2aff7Sartem 		is_disc = FALSE;
48618c2aff7Sartem 	}
48718c2aff7Sartem 
48818c2aff7Sartem 	drop_privileges ();
48918c2aff7Sartem 
49018c2aff7Sartem 	setup_logger ();
49118c2aff7Sartem 
49218c2aff7Sartem 	dbus_error_init (&error);
49318c2aff7Sartem 	if ((ctx = libhal_ctx_init_direct (&error)) == NULL)
49418c2aff7Sartem 		goto out;
49518c2aff7Sartem 
49618c2aff7Sartem 	HAL_DEBUG (("Doing probe-volume for %s\n", device_file));
49718c2aff7Sartem 
49818c2aff7Sartem 	fd = open (devpath, O_RDONLY | O_NONBLOCK);
49918c2aff7Sartem 	if (fd < 0) {
50018c2aff7Sartem 		goto out;
50118c2aff7Sartem 	}
50218c2aff7Sartem 	rfd = open (rdevpath, O_RDONLY | O_NONBLOCK);
50318c2aff7Sartem 	if (rfd < 0) {
50418c2aff7Sartem 		goto out;
50518c2aff7Sartem 	}
50618c2aff7Sartem 
50718c2aff7Sartem 	/* if it's a floppy with no media, bail out */
50818c2aff7Sartem 	if (ioctl(rfd, FDGETCHANGE, &fdc) == 0) {
50918c2aff7Sartem 		is_floppy = TRUE;
51018c2aff7Sartem 		if (fdc & FDGC_CURRENT) {
51118c2aff7Sartem 			goto out;
51218c2aff7Sartem 		}
51318c2aff7Sartem 	}
51418c2aff7Sartem 
51518c2aff7Sartem 	/* block size and total size */
51618c2aff7Sartem 	if (ioctl(rfd, DKIOCGMEDIAINFO, &mi) != -1) {
51718c2aff7Sartem 		block_size = mi.dki_lbsize;
51818c2aff7Sartem 		vol_size = mi.dki_capacity * block_size;
519b96e88d7Sartem 	} else if (errno == ENXIO) {
520b96e88d7Sartem 		/* driver supports ioctl, but media is not available */
521b96e88d7Sartem 		goto out;
52218c2aff7Sartem 	} else {
523b96e88d7Sartem 		/* driver does not support ioctl, e.g. lofi */
52418c2aff7Sartem 		block_size = 512;
52518c2aff7Sartem 		vol_size = 0;
52618c2aff7Sartem 	}
52718c2aff7Sartem 	libhal_device_set_property_int (ctx, udi, "volume.block_size", block_size, &error);
52818c2aff7Sartem 	my_dbus_error_free (&error);
52918c2aff7Sartem 	libhal_device_set_property_uint64 (ctx, udi, "volume.size", vol_size, &error);
53018c2aff7Sartem 	my_dbus_error_free (&error);
53118c2aff7Sartem 
53218c2aff7Sartem 	if (is_disc) {
533b941d3fcSartem 		if (!probe_disc (rfd, ctx, udi, &has_data, &has_audio)) {
53418c2aff7Sartem 			HAL_DEBUG (("probe_disc failed, skipping fstyp"));
53518c2aff7Sartem 			goto out;
53618c2aff7Sartem 		}
537b941d3fcSartem 		/* with audio present, create volume even if fs probing fails */
538b941d3fcSartem 		if (has_audio) {
539b941d3fcSartem 			ret = 0;
540b941d3fcSartem 		}
54118c2aff7Sartem 	}
54218c2aff7Sartem 
543b941d3fcSartem 	if (!has_data) {
54418c2aff7Sartem 		goto skip_fs;
54518c2aff7Sartem 	}
54618c2aff7Sartem 
54718c2aff7Sartem 	/* don't support partitioned floppy */
54818c2aff7Sartem 	if (is_floppy) {
54918c2aff7Sartem 		goto skip_part;
55018c2aff7Sartem 	}
55118c2aff7Sartem 
55218c2aff7Sartem 	/*
55318c2aff7Sartem 	 * first get partitioning info
55418c2aff7Sartem 	 */
55518c2aff7Sartem 	if (is_dos) {
55618c2aff7Sartem 		/* for a dos drive find partition offset */
557422ee277Sartem 		if (!find_dos_drive(fd, dos_num, block_size, &probe_offset)) {
55818c2aff7Sartem 			goto out;
55918c2aff7Sartem 		}
56018c2aff7Sartem 		partition_scheme = "mbr";
561422ee277Sartem 		partition_start = (dbus_uint64_t)probe_offset;
56218c2aff7Sartem 		partition_number = dos_num;
56318c2aff7Sartem 	} else {
564342440ecSPrasad Singamsetty 		if ((partition_number = read_extvtoc(rfd, &vtoc)) >= 0) {
56518c2aff7Sartem 			if (!vtoc_one_slice_entire_disk(&vtoc)) {
56618c2aff7Sartem 				partition_scheme = "smi";
56718c2aff7Sartem 				if (partition_number < vtoc.v_nparts) {
56818c2aff7Sartem 					if (vtoc.v_part[partition_number].p_size == 0) {
56918c2aff7Sartem 						HAL_DEBUG (("zero size partition"));
57018c2aff7Sartem 					}
57118c2aff7Sartem 					partition_start = vtoc.v_part[partition_number].p_start * block_size;
57218c2aff7Sartem 				}
57318c2aff7Sartem 			}
57418c2aff7Sartem 		} else if ((partition_number = efi_alloc_and_read(rfd, &gpt)) >= 0) {
57518c2aff7Sartem 			partition_scheme = "gpt";
57618c2aff7Sartem 			if (partition_number < gpt->efi_nparts) {
57718c2aff7Sartem 				if (gpt->efi_parts[partition_number].p_size == 0) {
57818c2aff7Sartem 					HAL_DEBUG (("zero size partition"));
57918c2aff7Sartem 				}
58018c2aff7Sartem 				partition_start = gpt->efi_parts[partition_number].p_start * block_size;
58118c2aff7Sartem 			}
58218c2aff7Sartem 			efi_free(gpt);
58318c2aff7Sartem 		}
58418c2aff7Sartem 		probe_offset = 0;
58518c2aff7Sartem 	}
58618c2aff7Sartem 
58718c2aff7Sartem 	if (partition_scheme != NULL) {
58818c2aff7Sartem 		libhal_device_set_property_string (ctx, udi, "volume.partition.scheme", partition_scheme, &error);
58918c2aff7Sartem 		my_dbus_error_free (&error);
59018c2aff7Sartem 		libhal_device_set_property_int (ctx, udi, "volume.partition.number", partition_number, &error);
59118c2aff7Sartem 		my_dbus_error_free (&error);
59218c2aff7Sartem 		libhal_device_set_property_uint64 (ctx, udi, "volume.partition.start", partition_start, &error);
59318c2aff7Sartem 		my_dbus_error_free (&error);
59418c2aff7Sartem 		libhal_device_set_property_bool (ctx, udi, "volume.is_partition", TRUE, &error);
59518c2aff7Sartem 		my_dbus_error_free (&error);
59618c2aff7Sartem 	} else {
59718c2aff7Sartem 		libhal_device_set_property_bool (ctx, udi, "volume.is_partition", FALSE, &error);
59818c2aff7Sartem 		my_dbus_error_free (&error);
59918c2aff7Sartem 	}
60018c2aff7Sartem 
60118c2aff7Sartem 	/*
60218c2aff7Sartem 	 * ignore duplicate partitions
60318c2aff7Sartem 	 */
60418c2aff7Sartem 	if ((volumes = libhal_manager_find_device_string_match (
60518c2aff7Sartem 	    ctx, "block.storage_device", storage_device, &num_volumes, &error)) != NULL) {
60618c2aff7Sartem 		my_dbus_error_free (&error);
60718c2aff7Sartem 		for (i = 0; i < num_volumes; i++) {
60818c2aff7Sartem 			if (strcmp (udi, volumes[i]) == 0) {
60918c2aff7Sartem 				continue; /* skip self */
61018c2aff7Sartem 			}
61118c2aff7Sartem 			v_start = libhal_device_get_property_uint64 (ctx, volumes[i], "volume.partition.start", &error);
61218c2aff7Sartem 			if (dbus_error_is_set(&error)) {
61318c2aff7Sartem 				dbus_error_free(&error);
61418c2aff7Sartem 				continue;
61518c2aff7Sartem 			}
61618c2aff7Sartem 			if (v_start == partition_start) {
61718c2aff7Sartem 				HAL_DEBUG (("duplicate partition"));
61818c2aff7Sartem 				goto out;
61918c2aff7Sartem 			}
62018c2aff7Sartem 		}
62118c2aff7Sartem 		libhal_free_string_array (volumes);
62218c2aff7Sartem 	}
62318c2aff7Sartem 
62418c2aff7Sartem skip_part:
62518c2aff7Sartem 
62618c2aff7Sartem 	/*
62718c2aff7Sartem 	 * now determine fs type
628b941d3fcSartem 	 *
629b941d3fcSartem 	 * XXX We could get better performance from block device,
630b941d3fcSartem 	 * but for now we use raw device because:
631b941d3fcSartem 	 *
632b941d3fcSartem 	 * - fstyp_udfs has a bug that it only works on raw
633b941d3fcSartem 	 *
634b941d3fcSartem 	 * - sd has a bug that causes extremely slow reads
635b941d3fcSartem 	 *   and incorrect probing of hybrid audio/data media
63618c2aff7Sartem 	 */
637b941d3fcSartem 	if (fstyp_init(rfd, probe_offset, NULL, &fstyp_handle) != 0) {
63818c2aff7Sartem 		HAL_DEBUG (("fstyp_init failed"));
63918c2aff7Sartem 		goto out;
64018c2aff7Sartem 	}
64118c2aff7Sartem 	if ((fstyp_ident(fstyp_handle, NULL, &fstype) != 0) ||
64218c2aff7Sartem 	    (fstyp_get_attr(fstyp_handle, &fsattr) != 0)) {
64318c2aff7Sartem 		HAL_DEBUG (("fstyp ident or get_attr failed"));
64418c2aff7Sartem 		fstyp_fini(fstyp_handle);
64518c2aff7Sartem 		goto out;
64618c2aff7Sartem 	}
64718c2aff7Sartem 	set_fstyp_properties (ctx, udi, fstype, fsattr);
6487544909dSartem 
6497544909dSartem 	if (strcmp (fstype, "hsfs") == 0) {
6507544909dSartem 		hsfs_contents (fd, probe_offset, ctx, udi);
6517544909dSartem 	}
6527544909dSartem 
65318c2aff7Sartem 	fstyp_fini(fstyp_handle);
65418c2aff7Sartem 
65518c2aff7Sartem skip_fs:
65618c2aff7Sartem 
65718c2aff7Sartem 	ret = 0;
65818c2aff7Sartem 
65918c2aff7Sartem out:
66018c2aff7Sartem 	if (fd >= 0)
66118c2aff7Sartem 		close (fd);
66218c2aff7Sartem 	if (rfd >= 0)
66318c2aff7Sartem 		close (rfd);
66418c2aff7Sartem 
66518c2aff7Sartem 	if (ctx != NULL) {
66618c2aff7Sartem 		my_dbus_error_free (&error);
66718c2aff7Sartem 		libhal_ctx_shutdown (ctx, &error);
66818c2aff7Sartem 		libhal_ctx_free (ctx);
66918c2aff7Sartem 	}
67018c2aff7Sartem 
67118c2aff7Sartem 	return ret;
67218c2aff7Sartem 
67318c2aff7Sartem }
674