xref: /illumos-gate/usr/src/cmd/fstyp/fstyp.c (revision 342440ec)
10e42dee6Sartem /*
20e42dee6Sartem  * CDDL HEADER START
30e42dee6Sartem  *
40e42dee6Sartem  * The contents of this file are subject to the terms of the
50e42dee6Sartem  * Common Development and Distribution License (the "License").
60e42dee6Sartem  * You may not use this file except in compliance with the License.
70e42dee6Sartem  *
80e42dee6Sartem  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90e42dee6Sartem  * or http://www.opensolaris.org/os/licensing.
100e42dee6Sartem  * See the License for the specific language governing permissions
110e42dee6Sartem  * and limitations under the License.
120e42dee6Sartem  *
130e42dee6Sartem  * When distributing Covered Code, include this CDDL HEADER in each
140e42dee6Sartem  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150e42dee6Sartem  * If applicable, add the following below this CDDL HEADER, with the
160e42dee6Sartem  * fields enclosed by brackets "[]" replaced with your own identifying
170e42dee6Sartem  * information: Portions Copyright [yyyy] [name of copyright owner]
180e42dee6Sartem  *
190e42dee6Sartem  * CDDL HEADER END
200e42dee6Sartem  */
210e42dee6Sartem /*
22ca29f3daSprabahar  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230e42dee6Sartem  * Use is subject to license terms.
240e42dee6Sartem  */
250e42dee6Sartem 
260e42dee6Sartem #include <fcntl.h>
270e42dee6Sartem #include <stdio.h>
280e42dee6Sartem #include <stdlib.h>
290e42dee6Sartem #include <sys/types.h>
300e42dee6Sartem #include <sys/stat.h>
310e42dee6Sartem #include <unistd.h>
320e42dee6Sartem #include <libintl.h>
330e42dee6Sartem #include <locale.h>
340e42dee6Sartem #include <string.h>
350e42dee6Sartem #include <strings.h>
360e42dee6Sartem #include <errno.h>
370e42dee6Sartem #include <dirent.h>
380e42dee6Sartem #include <dlfcn.h>
390e42dee6Sartem #include <sys/wait.h>
400e42dee6Sartem #include <sys/fstyp.h>
41ca29f3daSprabahar #include <sys/dkio.h>
42ca29f3daSprabahar #include <sys/param.h>
430e42dee6Sartem #include <libfstyp.h>
440e42dee6Sartem #include <sys/dktp/fdisk.h>
450e42dee6Sartem #include <sys/fs/pc_label.h>
460e42dee6Sartem 
47f5ac0e94Smc #include "libadm.h"
48f5ac0e94Smc 
490e42dee6Sartem #define	FSTYP_LIBFS_DIR	"/usr/lib/fs"
500e42dee6Sartem 
510e42dee6Sartem static const char *getmodfsname();
520e42dee6Sartem static char *getexecpathname();
530e42dee6Sartem static void dump_nvlist(nvlist_t *list, int indent);
540e42dee6Sartem static boolean_t dos_to_dev(char *path, char **devpath, int *num);
55ca29f3daSprabahar static boolean_t find_dos_drive(int fd, int num, off_t *offset);
560e42dee6Sartem static void run_legacy_cmds(int fd, char *device, int vflag);
570e42dee6Sartem static int run_cmd(char *path, char *arg0, char *arg1, char *arg2);
580e42dee6Sartem 
590e42dee6Sartem 
600e42dee6Sartem static void
610e42dee6Sartem usage(void)
620e42dee6Sartem {
630e42dee6Sartem 	(void) fprintf(stderr, gettext("Usage: fstyp [-av] <device>\n"));
640e42dee6Sartem 	exit(1);
650e42dee6Sartem }
660e42dee6Sartem 
670e42dee6Sartem int
680e42dee6Sartem main(int argc, char **argv)
690e42dee6Sartem {
700e42dee6Sartem 	int		fd = -1;
710e42dee6Sartem 	int		c;
720e42dee6Sartem 	int		aflag = 0;
730e42dee6Sartem 	int		vflag = 0;
740e42dee6Sartem 	int		indent = 0;
750e42dee6Sartem 	char		*devpath;
760e42dee6Sartem 	boolean_t	is_dos;
77ca29f3daSprabahar 	int		dos_num;
780e42dee6Sartem 	off_t		offset = 0;
790e42dee6Sartem 	nvlist_t	*attr = NULL;
800e42dee6Sartem 	fstyp_handle_t	h = NULL;
810e42dee6Sartem 	const char	*modfsname;
820e42dee6Sartem 	const char	*fsname;
830e42dee6Sartem 	int		error = FSTYP_ERR_NO_MATCH;
840e42dee6Sartem 
850e42dee6Sartem 	(void) setlocale(LC_ALL, "");
860e42dee6Sartem 
870e42dee6Sartem #if !defined(TEXT_DOMAIN)
880e42dee6Sartem #define	TEXT_DOMAIN "SYS_TEST"
890e42dee6Sartem #endif
900e42dee6Sartem 	(void) textdomain(TEXT_DOMAIN);
910e42dee6Sartem 
920e42dee6Sartem 	while ((c = getopt(argc, argv, "av")) != -1) {
930e42dee6Sartem 		switch (c) {
940e42dee6Sartem 		case 'a':
950e42dee6Sartem 			aflag = 1;
960e42dee6Sartem 			break;
970e42dee6Sartem 		case 'v':
980e42dee6Sartem 			vflag = 1;
990e42dee6Sartem 			break;
1000e42dee6Sartem 		default:
1010e42dee6Sartem 			usage();
1020e42dee6Sartem 			break;
1030e42dee6Sartem 		}
1040e42dee6Sartem 	}
1050e42dee6Sartem 
1060e42dee6Sartem 	argv += optind;
1070e42dee6Sartem 	argc -= optind;
1080e42dee6Sartem 
1090e42dee6Sartem 	if (argc != 1) {
1100e42dee6Sartem 		usage();
1110e42dee6Sartem 	}
1120e42dee6Sartem 
1130e42dee6Sartem 	modfsname = getmodfsname();
1140e42dee6Sartem 
1150e42dee6Sartem 	/*
1160e42dee6Sartem 	 * Open device, find partition offset if requested
1170e42dee6Sartem 	 */
1180e42dee6Sartem 	if (!(is_dos = dos_to_dev(argv[0], &devpath, &dos_num))) {
1190e42dee6Sartem 		devpath = argv[0];
1200e42dee6Sartem 	}
1210e42dee6Sartem 	if ((fd = open(devpath, O_RDONLY)) < 0) {
1220e42dee6Sartem 		error = FSTYP_ERR_DEV_OPEN;
1230e42dee6Sartem 		goto out;
1240e42dee6Sartem 	}
1250e42dee6Sartem 	if (is_dos) {
126ca29f3daSprabahar 		if (!find_dos_drive(fd, dos_num, &offset)) {
1270e42dee6Sartem 			error = FSTYP_ERR_NO_PARTITION;
1280e42dee6Sartem 			goto out;
1290e42dee6Sartem 		}
1300e42dee6Sartem 	}
1310e42dee6Sartem 
1320e42dee6Sartem 	/*
1330e42dee6Sartem 	 * Use libfstyp to identify filesystem
1340e42dee6Sartem 	 */
1350e42dee6Sartem 	if ((error = fstyp_init(fd, offset, NULL, &h)) != 0) {
1360e42dee6Sartem 		goto out;
1370e42dee6Sartem 	}
1380e42dee6Sartem 	if ((error = fstyp_ident(h, modfsname, &fsname)) != 0) {
1390e42dee6Sartem 		fstyp_fini(h);
1400e42dee6Sartem 		h = NULL;
1410e42dee6Sartem 
1420e42dee6Sartem 		run_legacy_cmds(fd, argv[0], vflag);
1430e42dee6Sartem 
1440e42dee6Sartem 		goto out;
1450e42dee6Sartem 	}
1460e42dee6Sartem 
1470e42dee6Sartem 	(void) printf("%s\n", fsname);
1480e42dee6Sartem 
1490e42dee6Sartem 	/*
1500e42dee6Sartem 	 * Output additional info if requested
1510e42dee6Sartem 	 */
1520e42dee6Sartem 	if (vflag) {
1530e42dee6Sartem 		error = fstyp_dump(h, stdout, stderr);
1540e42dee6Sartem 	}
1550e42dee6Sartem 	if (aflag || (vflag && (error == FSTYP_ERR_NOP))) {
1560e42dee6Sartem 		if ((error = fstyp_get_attr(h, &attr)) != 0) {
1570e42dee6Sartem 			goto out;
1580e42dee6Sartem 		}
1590e42dee6Sartem 		dump_nvlist(attr, indent);
1600e42dee6Sartem 	}
1610e42dee6Sartem 
1620e42dee6Sartem out:
1630e42dee6Sartem 	if (error != 0) {
1640e42dee6Sartem 		(void) fprintf(stderr, gettext("unknown_fstyp (%s)\n"),
1650e42dee6Sartem 		    fstyp_strerror(h, error));
1660e42dee6Sartem 	}
1670e42dee6Sartem 	if (h != NULL) {
1680e42dee6Sartem 		fstyp_fini(h);
1690e42dee6Sartem 	}
1700e42dee6Sartem 	if (fd >= 0) {
1710e42dee6Sartem 		(void) close(fd);
1720e42dee6Sartem 	}
1730e42dee6Sartem 	if (devpath != argv[0]) {
1740e42dee6Sartem 		free(devpath);
1750e42dee6Sartem 	}
1760e42dee6Sartem 	return (error);
1770e42dee6Sartem 
1780e42dee6Sartem }
1790e42dee6Sartem 
1800e42dee6Sartem #define	NVP(elem, type, vtype, ptype, format) { \
1810e42dee6Sartem 	vtype	value; \
1820e42dee6Sartem \
1830e42dee6Sartem 	(void) nvpair_value_##type(elem, &value); \
1840e42dee6Sartem 	(void) printf("%*s%s: " format "\n", indent, "", \
1850e42dee6Sartem 	    nvpair_name(elem), (ptype)value); \
1860e42dee6Sartem }
1870e42dee6Sartem 
1880e42dee6Sartem #define	NVPA(elem, type, vtype, ptype, format) { \
1890e42dee6Sartem 	uint_t	i, count; \
1900e42dee6Sartem 	vtype	*value;  \
1910e42dee6Sartem \
1920e42dee6Sartem 	(void) nvpair_value_##type(elem, &value, &count); \
1930e42dee6Sartem 	for (i = 0; i < count; i++) { \
1940e42dee6Sartem 		(void) printf("%*s%s[%d]: " format "\n", indent, "", \
1950e42dee6Sartem 		    nvpair_name(elem), i, (ptype)value[i]); \
1960e42dee6Sartem 	} \
1970e42dee6Sartem }
1980e42dee6Sartem 
1990e42dee6Sartem static void
2000e42dee6Sartem dump_nvlist(nvlist_t *list, int indent)
2010e42dee6Sartem {
2020e42dee6Sartem 	nvpair_t	*elem = NULL;
2030e42dee6Sartem 	boolean_t	bool_value;
2040e42dee6Sartem 	nvlist_t	*nvlist_value;
2050e42dee6Sartem 	nvlist_t	**nvlist_array_value;
2060e42dee6Sartem 	uint_t		i, count;
2070e42dee6Sartem 
2080e42dee6Sartem 	if (list == NULL) {
2090e42dee6Sartem 		return;
2100e42dee6Sartem 	}
2110e42dee6Sartem 
2120e42dee6Sartem 	while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {
2130e42dee6Sartem 		switch (nvpair_type(elem)) {
2140e42dee6Sartem 		case DATA_TYPE_BOOLEAN_VALUE:
2150e42dee6Sartem 			(void) nvpair_value_boolean_value(elem, &bool_value);
2160e42dee6Sartem 			(void) printf("%*s%s: %s\n", indent, "",
2170e42dee6Sartem 			    nvpair_name(elem), bool_value ? "true" : "false");
2180e42dee6Sartem 			break;
2190e42dee6Sartem 
2200e42dee6Sartem 		case DATA_TYPE_BYTE:
2210e42dee6Sartem 			NVP(elem, byte, uchar_t, int, "%u");
2220e42dee6Sartem 			break;
2230e42dee6Sartem 
2240e42dee6Sartem 		case DATA_TYPE_INT8:
2250e42dee6Sartem 			NVP(elem, int8, int8_t, int, "%d");
2260e42dee6Sartem 			break;
2270e42dee6Sartem 
2280e42dee6Sartem 		case DATA_TYPE_UINT8:
2290e42dee6Sartem 			NVP(elem, uint8, uint8_t, int, "%u");
2300e42dee6Sartem 			break;
2310e42dee6Sartem 
2320e42dee6Sartem 		case DATA_TYPE_INT16:
2330e42dee6Sartem 			NVP(elem, int16, int16_t, int, "%d");
2340e42dee6Sartem 			break;
2350e42dee6Sartem 
2360e42dee6Sartem 		case DATA_TYPE_UINT16:
2370e42dee6Sartem 			NVP(elem, uint16, uint16_t, int, "%u");
2380e42dee6Sartem 			break;
2390e42dee6Sartem 
2400e42dee6Sartem 		case DATA_TYPE_INT32:
2410e42dee6Sartem 			NVP(elem, int32, int32_t, long, "%ld");
2420e42dee6Sartem 			break;
2430e42dee6Sartem 
2440e42dee6Sartem 		case DATA_TYPE_UINT32:
2450e42dee6Sartem 			NVP(elem, uint32, uint32_t, ulong_t, "%lu");
2460e42dee6Sartem 			break;
2470e42dee6Sartem 
2480e42dee6Sartem 		case DATA_TYPE_INT64:
2490e42dee6Sartem 			NVP(elem, int64, int64_t, longlong_t, "%lld");
2500e42dee6Sartem 			break;
2510e42dee6Sartem 
2520e42dee6Sartem 		case DATA_TYPE_UINT64:
2530e42dee6Sartem 			NVP(elem, uint64, uint64_t, u_longlong_t, "%llu");
2540e42dee6Sartem 			break;
2550e42dee6Sartem 
2560e42dee6Sartem 		case DATA_TYPE_STRING:
2570e42dee6Sartem 			NVP(elem, string, char *, char *, "'%s'");
2580e42dee6Sartem 			break;
2590e42dee6Sartem 
2600e42dee6Sartem 		case DATA_TYPE_BYTE_ARRAY:
2610e42dee6Sartem 			NVPA(elem, byte_array, uchar_t, int, "%u");
2620e42dee6Sartem 			break;
2630e42dee6Sartem 
2640e42dee6Sartem 		case DATA_TYPE_INT8_ARRAY:
2650e42dee6Sartem 			NVPA(elem, int8_array, int8_t, int, "%d");
2660e42dee6Sartem 			break;
2670e42dee6Sartem 
2680e42dee6Sartem 		case DATA_TYPE_UINT8_ARRAY:
2690e42dee6Sartem 			NVPA(elem, uint8_array, uint8_t, int, "%u");
2700e42dee6Sartem 			break;
2710e42dee6Sartem 
2720e42dee6Sartem 		case DATA_TYPE_INT16_ARRAY:
2730e42dee6Sartem 			NVPA(elem, int16_array, int16_t, int, "%d");
2740e42dee6Sartem 			break;
2750e42dee6Sartem 
2760e42dee6Sartem 		case DATA_TYPE_UINT16_ARRAY:
2770e42dee6Sartem 			NVPA(elem, uint16_array, uint16_t, int, "%u");
2780e42dee6Sartem 			break;
2790e42dee6Sartem 
2800e42dee6Sartem 		case DATA_TYPE_INT32_ARRAY:
2810e42dee6Sartem 			NVPA(elem, int32_array, int32_t, long, "%ld");
2820e42dee6Sartem 			break;
2830e42dee6Sartem 
2840e42dee6Sartem 		case DATA_TYPE_UINT32_ARRAY:
2850e42dee6Sartem 			NVPA(elem, uint32_array, uint32_t, ulong_t, "%lu");
2860e42dee6Sartem 			break;
2870e42dee6Sartem 
2880e42dee6Sartem 		case DATA_TYPE_INT64_ARRAY:
2890e42dee6Sartem 			NVPA(elem, int64_array, int64_t, longlong_t, "%lld");
2900e42dee6Sartem 			break;
2910e42dee6Sartem 
2920e42dee6Sartem 		case DATA_TYPE_UINT64_ARRAY:
2930e42dee6Sartem 			NVPA(elem, uint64_array, uint64_t, u_longlong_t,
2940e42dee6Sartem 			    "%llu");
2950e42dee6Sartem 			break;
2960e42dee6Sartem 
2970e42dee6Sartem 		case DATA_TYPE_STRING_ARRAY:
2980e42dee6Sartem 			NVPA(elem, string_array, char *, char *, "'%s'");
2990e42dee6Sartem 			break;
3000e42dee6Sartem 
3010e42dee6Sartem 		case DATA_TYPE_NVLIST:
3020e42dee6Sartem 			(void) nvpair_value_nvlist(elem, &nvlist_value);
3030e42dee6Sartem 			(void) printf("%*s%s:\n", indent, "",
3040e42dee6Sartem 			    nvpair_name(elem));
3050e42dee6Sartem 			dump_nvlist(nvlist_value, indent + 4);
3060e42dee6Sartem 			break;
3070e42dee6Sartem 
3080e42dee6Sartem 		case DATA_TYPE_NVLIST_ARRAY:
3090e42dee6Sartem 			(void) nvpair_value_nvlist_array(elem,
3100e42dee6Sartem 			    &nvlist_array_value, &count);
3110e42dee6Sartem 			for (i = 0; i < count; i++) {
3120e42dee6Sartem 				(void) printf("%*s%s[%u]:\n", indent, "",
3130e42dee6Sartem 				    nvpair_name(elem), i);
3140e42dee6Sartem 				dump_nvlist(nvlist_array_value[i], indent + 4);
3150e42dee6Sartem 			}
3160e42dee6Sartem 			break;
3170e42dee6Sartem 
3180e42dee6Sartem 		default:
3190e42dee6Sartem 			(void) printf(gettext("bad config type %d for %s\n"),
3200e42dee6Sartem 			    nvpair_type(elem), nvpair_name(elem));
3210e42dee6Sartem 		}
3220e42dee6Sartem 	}
3230e42dee6Sartem }
3240e42dee6Sartem 
3250e42dee6Sartem /*
3260e42dee6Sartem  * If the executable is a fs-specific hardlink, /usr/lib/fs/<fsname>/fstyp,
3270e42dee6Sartem  * return that fsname; otherwise return NULL.
3280e42dee6Sartem  */
3290e42dee6Sartem static const char *
3300e42dee6Sartem getmodfsname()
3310e42dee6Sartem {
3320e42dee6Sartem 	static char fsname_buf[FSTYPSZ + 1];
3330e42dee6Sartem 	char	*fsname = NULL;
3340e42dee6Sartem 	char	*path;
3350e42dee6Sartem 	char	*p;
3360e42dee6Sartem 	int	len;
3370e42dee6Sartem 
3380e42dee6Sartem 	if ((path = getexecpathname()) == NULL) {
3390e42dee6Sartem 		return (NULL);
3400e42dee6Sartem 	}
3410e42dee6Sartem 	if ((p = strrchr(path, '/')) != NULL) {
3420e42dee6Sartem 		*p = '\0';
3430e42dee6Sartem 		if ((p = strrchr(path, '/')) != NULL) {
3440e42dee6Sartem 			*p++ = '\0';
3450e42dee6Sartem 			len = strlen(p);
3460e42dee6Sartem 			if ((strcmp(path, FSTYP_LIBFS_DIR) == 0) &&
3470e42dee6Sartem 			    (len > 0) && (len < sizeof (fsname_buf))) {
3480e42dee6Sartem 				(void) strlcpy(fsname_buf, p,
3490e42dee6Sartem 				    sizeof (fsname_buf));
3500e42dee6Sartem 				fsname = fsname_buf;
3510e42dee6Sartem 			}
3520e42dee6Sartem 		}
3530e42dee6Sartem 	}
3540e42dee6Sartem 	free(path);
3550e42dee6Sartem 	return (fsname);
3560e42dee6Sartem }
3570e42dee6Sartem 
3580e42dee6Sartem /*
3590e42dee6Sartem  * Return executable's absolute pathname
3600e42dee6Sartem  */
3610e42dee6Sartem static char *
3620e42dee6Sartem getexecpathname()
3630e42dee6Sartem {
3640e42dee6Sartem 	size_t		size;
3650e42dee6Sartem 	const char	*execname;
3660e42dee6Sartem 	char		*cwd;
3670e42dee6Sartem 	char		*path;
3680e42dee6Sartem 	char		*rpath;
3690e42dee6Sartem 
3700e42dee6Sartem 	size = pathconf(".", _PC_PATH_MAX) + 1;
3710e42dee6Sartem 	path = malloc(size);
3720e42dee6Sartem 	rpath = malloc(size);
3730e42dee6Sartem 	cwd = getcwd(NULL, size);
3740e42dee6Sartem 	if ((path == NULL) || (rpath == NULL) || (cwd == NULL)) {
3750e42dee6Sartem 		goto out;
3760e42dee6Sartem 	}
3770e42dee6Sartem 	execname = getexecname();
3780e42dee6Sartem 
3790e42dee6Sartem 	if (execname[0] == '/') {
3800e42dee6Sartem 		(void) snprintf(path, size, "%s", execname);
3810e42dee6Sartem 	} else {
3820e42dee6Sartem 		(void) snprintf(path, size, "%s/%s", cwd, execname);
3830e42dee6Sartem 	}
3840e42dee6Sartem 	if (realpath(path, rpath) == NULL) {
3850e42dee6Sartem 		free(rpath);
3860e42dee6Sartem 		rpath = NULL;
3870e42dee6Sartem 	}
3880e42dee6Sartem 
3890e42dee6Sartem out:
3900e42dee6Sartem 	if (path != NULL) {
3910e42dee6Sartem 		free(path);
3920e42dee6Sartem 	}
3930e42dee6Sartem 	if (cwd != NULL) {
3940e42dee6Sartem 		free(cwd);
3950e42dee6Sartem 	}
3960e42dee6Sartem 	return (rpath);
3970e42dee6Sartem }
3980e42dee6Sartem 
3990e42dee6Sartem /*
4000e42dee6Sartem  * Separates dos notation device spec into device and drive number
4010e42dee6Sartem  */
4020e42dee6Sartem static boolean_t
4030e42dee6Sartem dos_to_dev(char *path, char **devpath, int *num)
4040e42dee6Sartem {
4050e42dee6Sartem 	char *p;
4060e42dee6Sartem 
4070e42dee6Sartem 	if ((p = strrchr(path, ':')) == NULL) {
4080e42dee6Sartem 		return (B_FALSE);
4090e42dee6Sartem 	}
4100e42dee6Sartem 	if ((*num = atoi(p + 1)) == 0) {
4110e42dee6Sartem 		return (B_FALSE);
4120e42dee6Sartem 	}
4130e42dee6Sartem 	p[0] = '\0';
414f5ac0e94Smc 	*devpath = getfullrawname(path);
4150e42dee6Sartem 	p[0] = ':';
416f5ac0e94Smc 	if (*devpath != NULL && **devpath == '\0') {
417f5ac0e94Smc 		free(*devpath);
418f5ac0e94Smc 		*devpath = NULL;
419f5ac0e94Smc 	}
4200e42dee6Sartem 	return (*devpath != NULL);
4210e42dee6Sartem }
4220e42dee6Sartem 
4230e42dee6Sartem static boolean_t
4240e42dee6Sartem is_dos_drive(uchar_t type)
4250e42dee6Sartem {
4262d700530Sartem 	return ((type == DOSOS12) || (type == DOSOS16) ||
4272d700530Sartem 	    (type == DOSHUGE) || (type == FDISK_WINDOWS) ||
4282d700530Sartem 	    (type == FDISK_EXT_WIN) || (type == FDISK_FAT95) ||
4292d700530Sartem 	    (type == DIAGPART));
4300e42dee6Sartem }
4310e42dee6Sartem 
4320e42dee6Sartem static boolean_t
4330e42dee6Sartem is_dos_extended(uchar_t id)
4340e42dee6Sartem {
4350e42dee6Sartem 	return ((id == EXTDOS) || (id == FDISK_EXTLBA));
4360e42dee6Sartem }
4370e42dee6Sartem 
4380e42dee6Sartem struct part_find_s {
4390e42dee6Sartem 	int	num;
4400e42dee6Sartem 	int	count;
4410e42dee6Sartem 	int	systid;
4420e42dee6Sartem 	int	r_systid;
443*342440ecSPrasad Singamsetty 	uint32_t	r_relsect;
444*342440ecSPrasad Singamsetty 	uint32_t	r_numsect;
4450e42dee6Sartem };
4460e42dee6Sartem 
4470e42dee6Sartem enum { WALK_CONTINUE, WALK_TERMINATE };
4480e42dee6Sartem 
4490e42dee6Sartem /*
4500e42dee6Sartem  * Walk partition tables and invoke a callback for each.
4510e42dee6Sartem  */
4520e42dee6Sartem static void
453*342440ecSPrasad Singamsetty walk_partitions(int fd, uint32_t startsec, off_t secsz,
454*342440ecSPrasad Singamsetty     int (*f)(void *, int, uint32_t, uint32_t), void *arg)
4550e42dee6Sartem {
4560e42dee6Sartem 	uint32_t buf[1024/4];
4570e42dee6Sartem 	int bufsize = 1024;
4580e42dee6Sartem 	struct mboot *mboot = (struct mboot *)&buf[0];
4590e42dee6Sartem 	struct ipart ipart[FD_NUMPART];
460*342440ecSPrasad Singamsetty 	uint32_t sec = startsec;
461*342440ecSPrasad Singamsetty 	uint32_t lastsec = sec + 1;
462*342440ecSPrasad Singamsetty 	uint32_t relsect;
4630e42dee6Sartem 	int ext = 0;
4640e42dee6Sartem 	int systid;
4650e42dee6Sartem 	boolean_t valid;
4660e42dee6Sartem 	int i;
4670e42dee6Sartem 
4680e42dee6Sartem 	while (sec != lastsec) {
469ca29f3daSprabahar 		if (pread(fd, buf, bufsize, (off_t)sec * secsz) != bufsize) {
4700e42dee6Sartem 			break;
4710e42dee6Sartem 		}
4720e42dee6Sartem 		lastsec = sec;
4730e42dee6Sartem 		if (ltohs(mboot->signature) != MBB_MAGIC) {
4740e42dee6Sartem 			break;
4750e42dee6Sartem 		}
4760e42dee6Sartem 		bcopy(mboot->parts, ipart, FD_NUMPART * sizeof (struct ipart));
4770e42dee6Sartem 
4780e42dee6Sartem 		for (i = 0; i < FD_NUMPART; i++) {
4790e42dee6Sartem 			systid = ipart[i].systid;
4800e42dee6Sartem 			relsect = sec + ltohi(ipart[i].relsect);
4810e42dee6Sartem 			if (systid == 0) {
4820e42dee6Sartem 				continue;
4830e42dee6Sartem 			}
4840e42dee6Sartem 			valid = B_TRUE;
4850e42dee6Sartem 			if (is_dos_extended(systid) && (sec == lastsec)) {
4860e42dee6Sartem 				sec = startsec + ltohi(ipart[i].relsect);
4870e42dee6Sartem 				if (ext++ == 0) {
4880e42dee6Sartem 					relsect = startsec = sec;
4890e42dee6Sartem 				} else {
4900e42dee6Sartem 					valid = B_FALSE;
4910e42dee6Sartem 				}
4920e42dee6Sartem 			}
4930e42dee6Sartem 			if (valid && f(arg, ipart[i].systid, relsect,
4940e42dee6Sartem 			    ltohi(ipart[i].numsect)) == WALK_TERMINATE) {
4950e42dee6Sartem 				return;
4960e42dee6Sartem 			}
4970e42dee6Sartem 		}
4980e42dee6Sartem 	}
4990e42dee6Sartem }
5000e42dee6Sartem 
5010e42dee6Sartem static int
502*342440ecSPrasad Singamsetty find_dos_drive_cb(void *arg, int systid, uint32_t relsect, uint32_t numsect)
5030e42dee6Sartem {
5040e42dee6Sartem 	struct part_find_s *p = arg;
5050e42dee6Sartem 
5060e42dee6Sartem 	if (is_dos_drive(systid)) {
5070e42dee6Sartem 		if (++p->count == p->num) {
5080e42dee6Sartem 			p->r_relsect = relsect;
5090e42dee6Sartem 			p->r_numsect = numsect;
5100e42dee6Sartem 			p->r_systid = systid;
5110e42dee6Sartem 			return (WALK_TERMINATE);
5120e42dee6Sartem 		}
5130e42dee6Sartem 	}
5140e42dee6Sartem 
5150e42dee6Sartem 	return (WALK_CONTINUE);
5160e42dee6Sartem }
5170e42dee6Sartem 
5180e42dee6Sartem /*
519ca29f3daSprabahar  * Given a dos drive number, return its relative offset in the drive.
5200e42dee6Sartem  */
5210e42dee6Sartem static boolean_t
522ca29f3daSprabahar find_dos_drive(int fd, int num, off_t *offset)
5230e42dee6Sartem {
524ca29f3daSprabahar 	struct dk_minfo mi;
525ca29f3daSprabahar 	off_t secsz;
5260e42dee6Sartem 	struct part_find_s p = { 0, 0, 0, 0, 0, 0 };
5270e42dee6Sartem 
5280e42dee6Sartem 	p.num = num;
5290e42dee6Sartem 
530ca29f3daSprabahar 	/*
531ca29f3daSprabahar 	 * It is possible that the media we are dealing with can have different
532ca29f3daSprabahar 	 * sector size than the default 512 bytes. Query the driver and check
533ca29f3daSprabahar 	 * whether the media has different sector size.
534ca29f3daSprabahar 	 */
535ca29f3daSprabahar 	if (ioctl(fd, DKIOCGMEDIAINFO, &mi) < 0)
536ca29f3daSprabahar 		secsz = DEV_BSIZE;
537ca29f3daSprabahar 	else
538ca29f3daSprabahar 		secsz = mi.dki_lbsize;
539ca29f3daSprabahar 
5400e42dee6Sartem 	if (num > 0) {
541ca29f3daSprabahar 		walk_partitions(fd, 0, secsz, find_dos_drive_cb, &p);
5420e42dee6Sartem 		if (p.count == num) {
543ca29f3daSprabahar 			*offset = secsz * (off_t)p.r_relsect;
5440e42dee6Sartem 			return (B_TRUE);
5450e42dee6Sartem 		}
5460e42dee6Sartem 	}
5470e42dee6Sartem 
5480e42dee6Sartem 	return (B_FALSE);
5490e42dee6Sartem }
5500e42dee6Sartem 
5510e42dee6Sartem /*
5520e42dee6Sartem  * libfstyp identification failed: as a last resort, try to
5530e42dee6Sartem  * find and run legacy /usr/lib/fs/<fsname>/fstyp commands.
5540e42dee6Sartem  */
5550e42dee6Sartem static void
5560e42dee6Sartem run_legacy_cmds(int fd, char *device, int vflag)
5570e42dee6Sartem {
5580e42dee6Sartem 	char		*lib_dir = FSTYP_LIBFS_DIR;
5590e42dee6Sartem 	char		*path;
5600e42dee6Sartem 	long		name_max;
5610e42dee6Sartem 	DIR		*dirp;
5620e42dee6Sartem 	struct dirent	*dp_mem, *dp;
5630e42dee6Sartem 	struct stat	st;
5640e42dee6Sartem 	fstyp_handle_t	h;
5650e42dee6Sartem 	int		error;
5660e42dee6Sartem 	char		*arg1, *arg2;
5670e42dee6Sartem 
5680e42dee6Sartem 	if (vflag) {
5690e42dee6Sartem 		arg1 = "-v";
5700e42dee6Sartem 		arg2 = device;
5710e42dee6Sartem 	} else {
5720e42dee6Sartem 		arg1 = device;
5730e42dee6Sartem 		arg2 = NULL;
5740e42dee6Sartem 	}
5750e42dee6Sartem 
5760e42dee6Sartem 	if ((dirp = opendir(lib_dir)) == NULL) {
5770e42dee6Sartem 		return;
5780e42dee6Sartem 	}
5790e42dee6Sartem 
5800e42dee6Sartem 	name_max = pathconf(lib_dir, _PC_NAME_MAX);
5810e42dee6Sartem 	path = calloc(1, name_max + 1);
5820e42dee6Sartem 	dp = dp_mem = calloc(1, sizeof (struct dirent) + name_max + 1);
5830e42dee6Sartem 	if ((path == NULL) || (dp_mem == NULL)) {
5840e42dee6Sartem 		goto out;
5850e42dee6Sartem 	}
5860e42dee6Sartem 
5870e42dee6Sartem 	while ((readdir_r(dirp, dp, &dp) == 0) && (dp != NULL)) {
5880e42dee6Sartem 		if (dp->d_name[0] == '.') {
5890e42dee6Sartem 			continue;
5900e42dee6Sartem 		}
5910e42dee6Sartem 		(void) snprintf(path, name_max, "%s/%s", lib_dir, dp->d_name);
5920e42dee6Sartem 
5930e42dee6Sartem 		/* it's legacy if there's no libfstyp module for it */
5940e42dee6Sartem 		error = fstyp_init(fd, 0, path, &h);
5950e42dee6Sartem 		if (error != FSTYP_ERR_MOD_NOT_FOUND) {
5960e42dee6Sartem 			if (error == 0) {
5970e42dee6Sartem 				fstyp_fini(h);
5980e42dee6Sartem 			}
5990e42dee6Sartem 			continue;
6000e42dee6Sartem 		}
6010e42dee6Sartem 
6020e42dee6Sartem 		/* file must exist and be executable */
6030e42dee6Sartem 		(void) snprintf(path, name_max,
6040e42dee6Sartem 		    "%s/%s/fstyp", lib_dir, dp->d_name);
6050e42dee6Sartem 		if ((stat(path, &st) < 0) ||
6060e42dee6Sartem 		    ((st.st_mode & S_IXUSR) == 0)) {
6070e42dee6Sartem 			continue;
6080e42dee6Sartem 		}
6090e42dee6Sartem 
6100e42dee6Sartem 		if ((error = run_cmd(path, "fstyp", arg1, arg2)) == 0) {
6110e42dee6Sartem 			exit(0);
6120e42dee6Sartem 		}
6130e42dee6Sartem 	}
6140e42dee6Sartem 
6150e42dee6Sartem out:
6160e42dee6Sartem 	if (dp_mem != NULL) {
6170e42dee6Sartem 		free(dp_mem);
6180e42dee6Sartem 	}
6190e42dee6Sartem 	if (path != NULL) {
6200e42dee6Sartem 		free(path);
6210e42dee6Sartem 	}
6220e42dee6Sartem 	(void) closedir(dirp);
6230e42dee6Sartem }
6240e42dee6Sartem 
6250e42dee6Sartem static int
6260e42dee6Sartem run_cmd(char *path, char *arg0, char *arg1, char *arg2)
6270e42dee6Sartem {
6280e42dee6Sartem 	pid_t	pid;
6290e42dee6Sartem 	int	status = 1;
6300e42dee6Sartem 
6310e42dee6Sartem 	pid = fork();
6320e42dee6Sartem 	if (pid < 0) {
6330e42dee6Sartem 		return (1);
6340e42dee6Sartem 	} else if (pid == 0) {
6350e42dee6Sartem 		/* child */
6360e42dee6Sartem 		(void) execl(path, arg0, arg1, arg2, 0);
6370e42dee6Sartem 		exit(1);
6380e42dee6Sartem 	}
6390e42dee6Sartem 	/* parent */
6400e42dee6Sartem 	(void) wait(&status);
6410e42dee6Sartem 	return (status);
6420e42dee6Sartem }
643