xref: /illumos-gate/usr/src/cmd/fstyp/fstyp.c (revision 0e42dee6)
1*0e42dee6Sartem /*
2*0e42dee6Sartem  * CDDL HEADER START
3*0e42dee6Sartem  *
4*0e42dee6Sartem  * The contents of this file are subject to the terms of the
5*0e42dee6Sartem  * Common Development and Distribution License (the "License").
6*0e42dee6Sartem  * You may not use this file except in compliance with the License.
7*0e42dee6Sartem  *
8*0e42dee6Sartem  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*0e42dee6Sartem  * or http://www.opensolaris.org/os/licensing.
10*0e42dee6Sartem  * See the License for the specific language governing permissions
11*0e42dee6Sartem  * and limitations under the License.
12*0e42dee6Sartem  *
13*0e42dee6Sartem  * When distributing Covered Code, include this CDDL HEADER in each
14*0e42dee6Sartem  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*0e42dee6Sartem  * If applicable, add the following below this CDDL HEADER, with the
16*0e42dee6Sartem  * fields enclosed by brackets "[]" replaced with your own identifying
17*0e42dee6Sartem  * information: Portions Copyright [yyyy] [name of copyright owner]
18*0e42dee6Sartem  *
19*0e42dee6Sartem  * CDDL HEADER END
20*0e42dee6Sartem  */
21*0e42dee6Sartem /*
22*0e42dee6Sartem  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*0e42dee6Sartem  * Use is subject to license terms.
24*0e42dee6Sartem  */
25*0e42dee6Sartem 
26*0e42dee6Sartem #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*0e42dee6Sartem 
28*0e42dee6Sartem #include <fcntl.h>
29*0e42dee6Sartem #include <stdio.h>
30*0e42dee6Sartem #include <stdlib.h>
31*0e42dee6Sartem #include <sys/types.h>
32*0e42dee6Sartem #include <sys/stat.h>
33*0e42dee6Sartem #include <unistd.h>
34*0e42dee6Sartem #include <libintl.h>
35*0e42dee6Sartem #include <locale.h>
36*0e42dee6Sartem #include <string.h>
37*0e42dee6Sartem #include <strings.h>
38*0e42dee6Sartem #include <errno.h>
39*0e42dee6Sartem #include <dirent.h>
40*0e42dee6Sartem #include <dlfcn.h>
41*0e42dee6Sartem #include <sys/wait.h>
42*0e42dee6Sartem #include <sys/fstyp.h>
43*0e42dee6Sartem #include <libfstyp.h>
44*0e42dee6Sartem #include <sys/dktp/fdisk.h>
45*0e42dee6Sartem #include <sys/fs/pc_label.h>
46*0e42dee6Sartem 
47*0e42dee6Sartem #define	FSTYP_LIBFS_DIR	"/usr/lib/fs"
48*0e42dee6Sartem 
49*0e42dee6Sartem static const char *getmodfsname();
50*0e42dee6Sartem static char *getexecpathname();
51*0e42dee6Sartem static void dump_nvlist(nvlist_t *list, int indent);
52*0e42dee6Sartem static boolean_t dos_to_dev(char *path, char **devpath, int *num);
53*0e42dee6Sartem static boolean_t find_dos_drive(int fd, int num, int *relsect, int *numsect,
54*0e42dee6Sartem     int *systid);
55*0e42dee6Sartem static void run_legacy_cmds(int fd, char *device, int vflag);
56*0e42dee6Sartem static int run_cmd(char *path, char *arg0, char *arg1, char *arg2);
57*0e42dee6Sartem 
58*0e42dee6Sartem 
59*0e42dee6Sartem static void
60*0e42dee6Sartem usage(void)
61*0e42dee6Sartem {
62*0e42dee6Sartem 	(void) fprintf(stderr, gettext("Usage: fstyp [-av] <device>\n"));
63*0e42dee6Sartem 	exit(1);
64*0e42dee6Sartem }
65*0e42dee6Sartem 
66*0e42dee6Sartem int
67*0e42dee6Sartem main(int argc, char **argv)
68*0e42dee6Sartem {
69*0e42dee6Sartem 	int		fd = -1;
70*0e42dee6Sartem 	int		c;
71*0e42dee6Sartem 	int		aflag = 0;
72*0e42dee6Sartem 	int		vflag = 0;
73*0e42dee6Sartem 	int		indent = 0;
74*0e42dee6Sartem 	char		*devpath;
75*0e42dee6Sartem 	boolean_t	is_dos;
76*0e42dee6Sartem 	int		dos_num, systid, relsect, numsect;
77*0e42dee6Sartem 	off_t		offset = 0;
78*0e42dee6Sartem 	nvlist_t	*attr = NULL;
79*0e42dee6Sartem 	fstyp_handle_t	h = NULL;
80*0e42dee6Sartem 	const char	*modfsname;
81*0e42dee6Sartem 	const char	*fsname;
82*0e42dee6Sartem 	int		error = FSTYP_ERR_NO_MATCH;
83*0e42dee6Sartem 
84*0e42dee6Sartem 	(void) setlocale(LC_ALL, "");
85*0e42dee6Sartem 
86*0e42dee6Sartem #if !defined(TEXT_DOMAIN)
87*0e42dee6Sartem #define	TEXT_DOMAIN "SYS_TEST"
88*0e42dee6Sartem #endif
89*0e42dee6Sartem 	(void) textdomain(TEXT_DOMAIN);
90*0e42dee6Sartem 
91*0e42dee6Sartem 	while ((c = getopt(argc, argv, "av")) != -1) {
92*0e42dee6Sartem 		switch (c) {
93*0e42dee6Sartem 		case 'a':
94*0e42dee6Sartem 			aflag = 1;
95*0e42dee6Sartem 			break;
96*0e42dee6Sartem 		case 'v':
97*0e42dee6Sartem 			vflag = 1;
98*0e42dee6Sartem 			break;
99*0e42dee6Sartem 		default:
100*0e42dee6Sartem 			usage();
101*0e42dee6Sartem 			break;
102*0e42dee6Sartem 		}
103*0e42dee6Sartem 	}
104*0e42dee6Sartem 
105*0e42dee6Sartem 	argv += optind;
106*0e42dee6Sartem 	argc -= optind;
107*0e42dee6Sartem 
108*0e42dee6Sartem 	if (argc != 1) {
109*0e42dee6Sartem 		usage();
110*0e42dee6Sartem 	}
111*0e42dee6Sartem 
112*0e42dee6Sartem 	modfsname = getmodfsname();
113*0e42dee6Sartem 
114*0e42dee6Sartem 	/*
115*0e42dee6Sartem 	 * Open device, find partition offset if requested
116*0e42dee6Sartem 	 */
117*0e42dee6Sartem 	if (!(is_dos = dos_to_dev(argv[0], &devpath, &dos_num))) {
118*0e42dee6Sartem 		devpath = argv[0];
119*0e42dee6Sartem 	}
120*0e42dee6Sartem 	if ((fd = open(devpath, O_RDONLY)) < 0) {
121*0e42dee6Sartem 		error = FSTYP_ERR_DEV_OPEN;
122*0e42dee6Sartem 		goto out;
123*0e42dee6Sartem 	}
124*0e42dee6Sartem 	if (is_dos) {
125*0e42dee6Sartem 		if (find_dos_drive(fd, dos_num, &relsect, &numsect, &systid)) {
126*0e42dee6Sartem 			offset = (off_t)relsect * 512;
127*0e42dee6Sartem 		} else {
128*0e42dee6Sartem 			error = FSTYP_ERR_NO_PARTITION;
129*0e42dee6Sartem 			goto out;
130*0e42dee6Sartem 		}
131*0e42dee6Sartem 	}
132*0e42dee6Sartem 
133*0e42dee6Sartem 	/*
134*0e42dee6Sartem 	 * Use libfstyp to identify filesystem
135*0e42dee6Sartem 	 */
136*0e42dee6Sartem 	if ((error = fstyp_init(fd, offset, NULL, &h)) != 0) {
137*0e42dee6Sartem 		goto out;
138*0e42dee6Sartem 	}
139*0e42dee6Sartem 	if ((error = fstyp_ident(h, modfsname, &fsname)) != 0) {
140*0e42dee6Sartem 		fstyp_fini(h);
141*0e42dee6Sartem 		h = NULL;
142*0e42dee6Sartem 
143*0e42dee6Sartem 		run_legacy_cmds(fd, argv[0], vflag);
144*0e42dee6Sartem 
145*0e42dee6Sartem 		goto out;
146*0e42dee6Sartem 	}
147*0e42dee6Sartem 
148*0e42dee6Sartem 	(void) printf("%s\n", fsname);
149*0e42dee6Sartem 
150*0e42dee6Sartem 	/*
151*0e42dee6Sartem 	 * Output additional info if requested
152*0e42dee6Sartem 	 */
153*0e42dee6Sartem 	if (vflag) {
154*0e42dee6Sartem 		error = fstyp_dump(h, stdout, stderr);
155*0e42dee6Sartem 	}
156*0e42dee6Sartem 	if (aflag || (vflag && (error == FSTYP_ERR_NOP))) {
157*0e42dee6Sartem 		if ((error = fstyp_get_attr(h, &attr)) != 0) {
158*0e42dee6Sartem 			goto out;
159*0e42dee6Sartem 		}
160*0e42dee6Sartem 		dump_nvlist(attr, indent);
161*0e42dee6Sartem 	}
162*0e42dee6Sartem 
163*0e42dee6Sartem out:
164*0e42dee6Sartem 	if (error != 0) {
165*0e42dee6Sartem 		(void) fprintf(stderr, gettext("unknown_fstyp (%s)\n"),
166*0e42dee6Sartem 		    fstyp_strerror(h, error));
167*0e42dee6Sartem 	}
168*0e42dee6Sartem 	if (h != NULL) {
169*0e42dee6Sartem 		fstyp_fini(h);
170*0e42dee6Sartem 	}
171*0e42dee6Sartem 	if (fd >= 0) {
172*0e42dee6Sartem 		(void) close(fd);
173*0e42dee6Sartem 	}
174*0e42dee6Sartem 	if (devpath != argv[0]) {
175*0e42dee6Sartem 		free(devpath);
176*0e42dee6Sartem 	}
177*0e42dee6Sartem 	return (error);
178*0e42dee6Sartem 
179*0e42dee6Sartem }
180*0e42dee6Sartem 
181*0e42dee6Sartem #define	NVP(elem, type, vtype, ptype, format) { \
182*0e42dee6Sartem 	vtype	value; \
183*0e42dee6Sartem \
184*0e42dee6Sartem 	(void) nvpair_value_##type(elem, &value); \
185*0e42dee6Sartem 	(void) printf("%*s%s: " format "\n", indent, "", \
186*0e42dee6Sartem 	    nvpair_name(elem), (ptype)value); \
187*0e42dee6Sartem }
188*0e42dee6Sartem 
189*0e42dee6Sartem #define	NVPA(elem, type, vtype, ptype, format) { \
190*0e42dee6Sartem 	uint_t	i, count; \
191*0e42dee6Sartem 	vtype	*value;  \
192*0e42dee6Sartem \
193*0e42dee6Sartem 	(void) nvpair_value_##type(elem, &value, &count); \
194*0e42dee6Sartem 	for (i = 0; i < count; i++) { \
195*0e42dee6Sartem 		(void) printf("%*s%s[%d]: " format "\n", indent, "", \
196*0e42dee6Sartem 		    nvpair_name(elem), i, (ptype)value[i]); \
197*0e42dee6Sartem 	} \
198*0e42dee6Sartem }
199*0e42dee6Sartem 
200*0e42dee6Sartem static void
201*0e42dee6Sartem dump_nvlist(nvlist_t *list, int indent)
202*0e42dee6Sartem {
203*0e42dee6Sartem 	nvpair_t	*elem = NULL;
204*0e42dee6Sartem 	boolean_t	bool_value;
205*0e42dee6Sartem 	nvlist_t	*nvlist_value;
206*0e42dee6Sartem 	nvlist_t	**nvlist_array_value;
207*0e42dee6Sartem 	uint_t		i, count;
208*0e42dee6Sartem 
209*0e42dee6Sartem 	if (list == NULL) {
210*0e42dee6Sartem 		return;
211*0e42dee6Sartem 	}
212*0e42dee6Sartem 
213*0e42dee6Sartem 	while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {
214*0e42dee6Sartem 		switch (nvpair_type(elem)) {
215*0e42dee6Sartem 		case DATA_TYPE_BOOLEAN_VALUE:
216*0e42dee6Sartem 			(void) nvpair_value_boolean_value(elem, &bool_value);
217*0e42dee6Sartem 			(void) printf("%*s%s: %s\n", indent, "",
218*0e42dee6Sartem 			    nvpair_name(elem), bool_value ? "true" : "false");
219*0e42dee6Sartem 			break;
220*0e42dee6Sartem 
221*0e42dee6Sartem 		case DATA_TYPE_BYTE:
222*0e42dee6Sartem 			NVP(elem, byte, uchar_t, int, "%u");
223*0e42dee6Sartem 			break;
224*0e42dee6Sartem 
225*0e42dee6Sartem 		case DATA_TYPE_INT8:
226*0e42dee6Sartem 			NVP(elem, int8, int8_t, int, "%d");
227*0e42dee6Sartem 			break;
228*0e42dee6Sartem 
229*0e42dee6Sartem 		case DATA_TYPE_UINT8:
230*0e42dee6Sartem 			NVP(elem, uint8, uint8_t, int, "%u");
231*0e42dee6Sartem 			break;
232*0e42dee6Sartem 
233*0e42dee6Sartem 		case DATA_TYPE_INT16:
234*0e42dee6Sartem 			NVP(elem, int16, int16_t, int, "%d");
235*0e42dee6Sartem 			break;
236*0e42dee6Sartem 
237*0e42dee6Sartem 		case DATA_TYPE_UINT16:
238*0e42dee6Sartem 			NVP(elem, uint16, uint16_t, int, "%u");
239*0e42dee6Sartem 			break;
240*0e42dee6Sartem 
241*0e42dee6Sartem 		case DATA_TYPE_INT32:
242*0e42dee6Sartem 			NVP(elem, int32, int32_t, long, "%ld");
243*0e42dee6Sartem 			break;
244*0e42dee6Sartem 
245*0e42dee6Sartem 		case DATA_TYPE_UINT32:
246*0e42dee6Sartem 			NVP(elem, uint32, uint32_t, ulong_t, "%lu");
247*0e42dee6Sartem 			break;
248*0e42dee6Sartem 
249*0e42dee6Sartem 		case DATA_TYPE_INT64:
250*0e42dee6Sartem 			NVP(elem, int64, int64_t, longlong_t, "%lld");
251*0e42dee6Sartem 			break;
252*0e42dee6Sartem 
253*0e42dee6Sartem 		case DATA_TYPE_UINT64:
254*0e42dee6Sartem 			NVP(elem, uint64, uint64_t, u_longlong_t, "%llu");
255*0e42dee6Sartem 			break;
256*0e42dee6Sartem 
257*0e42dee6Sartem 		case DATA_TYPE_STRING:
258*0e42dee6Sartem 			NVP(elem, string, char *, char *, "'%s'");
259*0e42dee6Sartem 			break;
260*0e42dee6Sartem 
261*0e42dee6Sartem 		case DATA_TYPE_BYTE_ARRAY:
262*0e42dee6Sartem 			NVPA(elem, byte_array, uchar_t, int, "%u");
263*0e42dee6Sartem 			break;
264*0e42dee6Sartem 
265*0e42dee6Sartem 		case DATA_TYPE_INT8_ARRAY:
266*0e42dee6Sartem 			NVPA(elem, int8_array, int8_t, int, "%d");
267*0e42dee6Sartem 			break;
268*0e42dee6Sartem 
269*0e42dee6Sartem 		case DATA_TYPE_UINT8_ARRAY:
270*0e42dee6Sartem 			NVPA(elem, uint8_array, uint8_t, int, "%u");
271*0e42dee6Sartem 			break;
272*0e42dee6Sartem 
273*0e42dee6Sartem 		case DATA_TYPE_INT16_ARRAY:
274*0e42dee6Sartem 			NVPA(elem, int16_array, int16_t, int, "%d");
275*0e42dee6Sartem 			break;
276*0e42dee6Sartem 
277*0e42dee6Sartem 		case DATA_TYPE_UINT16_ARRAY:
278*0e42dee6Sartem 			NVPA(elem, uint16_array, uint16_t, int, "%u");
279*0e42dee6Sartem 			break;
280*0e42dee6Sartem 
281*0e42dee6Sartem 		case DATA_TYPE_INT32_ARRAY:
282*0e42dee6Sartem 			NVPA(elem, int32_array, int32_t, long, "%ld");
283*0e42dee6Sartem 			break;
284*0e42dee6Sartem 
285*0e42dee6Sartem 		case DATA_TYPE_UINT32_ARRAY:
286*0e42dee6Sartem 			NVPA(elem, uint32_array, uint32_t, ulong_t, "%lu");
287*0e42dee6Sartem 			break;
288*0e42dee6Sartem 
289*0e42dee6Sartem 		case DATA_TYPE_INT64_ARRAY:
290*0e42dee6Sartem 			NVPA(elem, int64_array, int64_t, longlong_t, "%lld");
291*0e42dee6Sartem 			break;
292*0e42dee6Sartem 
293*0e42dee6Sartem 		case DATA_TYPE_UINT64_ARRAY:
294*0e42dee6Sartem 			NVPA(elem, uint64_array, uint64_t, u_longlong_t,
295*0e42dee6Sartem 			    "%llu");
296*0e42dee6Sartem 			break;
297*0e42dee6Sartem 
298*0e42dee6Sartem 		case DATA_TYPE_STRING_ARRAY:
299*0e42dee6Sartem 			NVPA(elem, string_array, char *, char *, "'%s'");
300*0e42dee6Sartem 			break;
301*0e42dee6Sartem 
302*0e42dee6Sartem 		case DATA_TYPE_NVLIST:
303*0e42dee6Sartem 			(void) nvpair_value_nvlist(elem, &nvlist_value);
304*0e42dee6Sartem 			(void) printf("%*s%s:\n", indent, "",
305*0e42dee6Sartem 			    nvpair_name(elem));
306*0e42dee6Sartem 			dump_nvlist(nvlist_value, indent + 4);
307*0e42dee6Sartem 			break;
308*0e42dee6Sartem 
309*0e42dee6Sartem 		case DATA_TYPE_NVLIST_ARRAY:
310*0e42dee6Sartem 			(void) nvpair_value_nvlist_array(elem,
311*0e42dee6Sartem 			    &nvlist_array_value, &count);
312*0e42dee6Sartem 			for (i = 0; i < count; i++) {
313*0e42dee6Sartem 				(void) printf("%*s%s[%u]:\n", indent, "",
314*0e42dee6Sartem 				    nvpair_name(elem), i);
315*0e42dee6Sartem 				dump_nvlist(nvlist_array_value[i], indent + 4);
316*0e42dee6Sartem 			}
317*0e42dee6Sartem 			break;
318*0e42dee6Sartem 
319*0e42dee6Sartem 		default:
320*0e42dee6Sartem 			(void) printf(gettext("bad config type %d for %s\n"),
321*0e42dee6Sartem 			    nvpair_type(elem), nvpair_name(elem));
322*0e42dee6Sartem 		}
323*0e42dee6Sartem 	}
324*0e42dee6Sartem }
325*0e42dee6Sartem 
326*0e42dee6Sartem /*
327*0e42dee6Sartem  * If the executable is a fs-specific hardlink, /usr/lib/fs/<fsname>/fstyp,
328*0e42dee6Sartem  * return that fsname; otherwise return NULL.
329*0e42dee6Sartem  */
330*0e42dee6Sartem static const char *
331*0e42dee6Sartem getmodfsname()
332*0e42dee6Sartem {
333*0e42dee6Sartem 	static char fsname_buf[FSTYPSZ + 1];
334*0e42dee6Sartem 	char	*fsname = NULL;
335*0e42dee6Sartem 	char	*path;
336*0e42dee6Sartem 	char	*p;
337*0e42dee6Sartem 	int	len;
338*0e42dee6Sartem 
339*0e42dee6Sartem 	if ((path = getexecpathname()) == NULL) {
340*0e42dee6Sartem 		return (NULL);
341*0e42dee6Sartem 	}
342*0e42dee6Sartem 	if ((p = strrchr(path, '/')) != NULL) {
343*0e42dee6Sartem 		*p = '\0';
344*0e42dee6Sartem 		if ((p = strrchr(path, '/')) != NULL) {
345*0e42dee6Sartem 			*p++ = '\0';
346*0e42dee6Sartem 			len = strlen(p);
347*0e42dee6Sartem 			if ((strcmp(path, FSTYP_LIBFS_DIR) == 0) &&
348*0e42dee6Sartem 			    (len > 0) && (len < sizeof (fsname_buf))) {
349*0e42dee6Sartem 				(void) strlcpy(fsname_buf, p,
350*0e42dee6Sartem 				    sizeof (fsname_buf));
351*0e42dee6Sartem 				fsname = fsname_buf;
352*0e42dee6Sartem 			}
353*0e42dee6Sartem 		}
354*0e42dee6Sartem 	}
355*0e42dee6Sartem 	free(path);
356*0e42dee6Sartem 	return (fsname);
357*0e42dee6Sartem }
358*0e42dee6Sartem 
359*0e42dee6Sartem /*
360*0e42dee6Sartem  * Return executable's absolute pathname
361*0e42dee6Sartem  */
362*0e42dee6Sartem static char *
363*0e42dee6Sartem getexecpathname()
364*0e42dee6Sartem {
365*0e42dee6Sartem 	size_t		size;
366*0e42dee6Sartem 	const char	*execname;
367*0e42dee6Sartem 	char		*cwd;
368*0e42dee6Sartem 	char		*path;
369*0e42dee6Sartem 	char		*rpath;
370*0e42dee6Sartem 
371*0e42dee6Sartem 	size = pathconf(".", _PC_PATH_MAX) + 1;
372*0e42dee6Sartem 	path = malloc(size);
373*0e42dee6Sartem 	rpath = malloc(size);
374*0e42dee6Sartem 	cwd = getcwd(NULL, size);
375*0e42dee6Sartem 	if ((path == NULL) || (rpath == NULL) || (cwd == NULL)) {
376*0e42dee6Sartem 		goto out;
377*0e42dee6Sartem 	}
378*0e42dee6Sartem 	execname = getexecname();
379*0e42dee6Sartem 
380*0e42dee6Sartem 	if (execname[0] == '/') {
381*0e42dee6Sartem 		(void) snprintf(path, size, "%s", execname);
382*0e42dee6Sartem 	} else {
383*0e42dee6Sartem 		(void) snprintf(path, size, "%s/%s", cwd, execname);
384*0e42dee6Sartem 	}
385*0e42dee6Sartem 	if (realpath(path, rpath) == NULL) {
386*0e42dee6Sartem 		free(rpath);
387*0e42dee6Sartem 		rpath = NULL;
388*0e42dee6Sartem 	}
389*0e42dee6Sartem 
390*0e42dee6Sartem out:
391*0e42dee6Sartem 	if (path != NULL) {
392*0e42dee6Sartem 		free(path);
393*0e42dee6Sartem 	}
394*0e42dee6Sartem 	if (cwd != NULL) {
395*0e42dee6Sartem 		free(cwd);
396*0e42dee6Sartem 	}
397*0e42dee6Sartem 	return (rpath);
398*0e42dee6Sartem }
399*0e42dee6Sartem 
400*0e42dee6Sartem /*
401*0e42dee6Sartem  * Separates dos notation device spec into device and drive number
402*0e42dee6Sartem  */
403*0e42dee6Sartem static boolean_t
404*0e42dee6Sartem dos_to_dev(char *path, char **devpath, int *num)
405*0e42dee6Sartem {
406*0e42dee6Sartem 	char *p;
407*0e42dee6Sartem 
408*0e42dee6Sartem 	if ((p = strrchr(path, ':')) == NULL) {
409*0e42dee6Sartem 		return (B_FALSE);
410*0e42dee6Sartem 	}
411*0e42dee6Sartem 	if ((*num = atoi(p + 1)) == 0) {
412*0e42dee6Sartem 		return (B_FALSE);
413*0e42dee6Sartem 	}
414*0e42dee6Sartem 	p[0] = '\0';
415*0e42dee6Sartem 	*devpath = strdup(path);
416*0e42dee6Sartem 	p[0] = ':';
417*0e42dee6Sartem 	return (*devpath != NULL);
418*0e42dee6Sartem }
419*0e42dee6Sartem 
420*0e42dee6Sartem static boolean_t
421*0e42dee6Sartem is_dos_drive(uchar_t type)
422*0e42dee6Sartem {
423*0e42dee6Sartem 	return ((type == 1) || (type == 4) || (type == 5) || (type == 6) ||
424*0e42dee6Sartem 	    ((type >= 8) && (type <= 0xf)));
425*0e42dee6Sartem }
426*0e42dee6Sartem 
427*0e42dee6Sartem static boolean_t
428*0e42dee6Sartem is_dos_extended(uchar_t id)
429*0e42dee6Sartem {
430*0e42dee6Sartem 	return ((id == EXTDOS) || (id == FDISK_EXTLBA));
431*0e42dee6Sartem }
432*0e42dee6Sartem 
433*0e42dee6Sartem struct part_find_s {
434*0e42dee6Sartem 	int	num;
435*0e42dee6Sartem 	int	count;
436*0e42dee6Sartem 	int	systid;
437*0e42dee6Sartem 	int	r_systid;
438*0e42dee6Sartem 	int	r_relsect;
439*0e42dee6Sartem 	int	r_numsect;
440*0e42dee6Sartem };
441*0e42dee6Sartem 
442*0e42dee6Sartem enum { WALK_CONTINUE, WALK_TERMINATE };
443*0e42dee6Sartem 
444*0e42dee6Sartem /*
445*0e42dee6Sartem  * Walk partition tables and invoke a callback for each.
446*0e42dee6Sartem  */
447*0e42dee6Sartem static void
448*0e42dee6Sartem walk_partitions(int fd, int startsec, int (*f)(void *, int, int, int),
449*0e42dee6Sartem     void *arg)
450*0e42dee6Sartem {
451*0e42dee6Sartem 	uint32_t buf[1024/4];
452*0e42dee6Sartem 	int bufsize = 1024;
453*0e42dee6Sartem 	struct mboot *mboot = (struct mboot *)&buf[0];
454*0e42dee6Sartem 	struct ipart ipart[FD_NUMPART];
455*0e42dee6Sartem 	int sec = startsec;
456*0e42dee6Sartem 	int lastsec = sec + 1;
457*0e42dee6Sartem 	int relsect;
458*0e42dee6Sartem 	int ext = 0;
459*0e42dee6Sartem 	int systid;
460*0e42dee6Sartem 	boolean_t valid;
461*0e42dee6Sartem 	int i;
462*0e42dee6Sartem 
463*0e42dee6Sartem 	while (sec != lastsec) {
464*0e42dee6Sartem 		if (pread(fd, buf, bufsize, (off_t)sec * 512) != bufsize) {
465*0e42dee6Sartem 			break;
466*0e42dee6Sartem 		}
467*0e42dee6Sartem 		lastsec = sec;
468*0e42dee6Sartem 		if (ltohs(mboot->signature) != MBB_MAGIC) {
469*0e42dee6Sartem 			break;
470*0e42dee6Sartem 		}
471*0e42dee6Sartem 		bcopy(mboot->parts, ipart, FD_NUMPART * sizeof (struct ipart));
472*0e42dee6Sartem 
473*0e42dee6Sartem 		for (i = 0; i < FD_NUMPART; i++) {
474*0e42dee6Sartem 			systid = ipart[i].systid;
475*0e42dee6Sartem 			relsect = sec + ltohi(ipart[i].relsect);
476*0e42dee6Sartem 			if (systid == 0) {
477*0e42dee6Sartem 				continue;
478*0e42dee6Sartem 			}
479*0e42dee6Sartem 			valid = B_TRUE;
480*0e42dee6Sartem 			if (is_dos_extended(systid) && (sec == lastsec)) {
481*0e42dee6Sartem 				sec = startsec + ltohi(ipart[i].relsect);
482*0e42dee6Sartem 				if (ext++ == 0) {
483*0e42dee6Sartem 					relsect = startsec = sec;
484*0e42dee6Sartem 				} else {
485*0e42dee6Sartem 					valid = B_FALSE;
486*0e42dee6Sartem 				}
487*0e42dee6Sartem 			}
488*0e42dee6Sartem 			if (valid && f(arg, ipart[i].systid, relsect,
489*0e42dee6Sartem 			    ltohi(ipart[i].numsect)) == WALK_TERMINATE) {
490*0e42dee6Sartem 				return;
491*0e42dee6Sartem 			}
492*0e42dee6Sartem 		}
493*0e42dee6Sartem 	}
494*0e42dee6Sartem }
495*0e42dee6Sartem 
496*0e42dee6Sartem static int
497*0e42dee6Sartem find_dos_drive_cb(void *arg, int systid, int relsect, int numsect)
498*0e42dee6Sartem {
499*0e42dee6Sartem 	struct part_find_s *p = arg;
500*0e42dee6Sartem 
501*0e42dee6Sartem 	if (is_dos_drive(systid)) {
502*0e42dee6Sartem 		if (++p->count == p->num) {
503*0e42dee6Sartem 			p->r_relsect = relsect;
504*0e42dee6Sartem 			p->r_numsect = numsect;
505*0e42dee6Sartem 			p->r_systid = systid;
506*0e42dee6Sartem 			return (WALK_TERMINATE);
507*0e42dee6Sartem 		}
508*0e42dee6Sartem 	}
509*0e42dee6Sartem 
510*0e42dee6Sartem 	return (WALK_CONTINUE);
511*0e42dee6Sartem }
512*0e42dee6Sartem 
513*0e42dee6Sartem /*
514*0e42dee6Sartem  * Given a dos drive number, return its relative sector number,
515*0e42dee6Sartem  * number of sectors in partition and the system id.
516*0e42dee6Sartem  */
517*0e42dee6Sartem static boolean_t
518*0e42dee6Sartem find_dos_drive(int fd, int num, int *relsect, int *numsect, int *systid)
519*0e42dee6Sartem {
520*0e42dee6Sartem 	struct part_find_s p = { 0, 0, 0, 0, 0, 0 };
521*0e42dee6Sartem 
522*0e42dee6Sartem 	p.num = num;
523*0e42dee6Sartem 
524*0e42dee6Sartem 	if (num > 0) {
525*0e42dee6Sartem 		walk_partitions(fd, 0, find_dos_drive_cb, &p);
526*0e42dee6Sartem 		if (p.count == num) {
527*0e42dee6Sartem 			*relsect = p.r_relsect;
528*0e42dee6Sartem 			*numsect = p.r_numsect;
529*0e42dee6Sartem 			*systid = p.r_systid;
530*0e42dee6Sartem 			return (B_TRUE);
531*0e42dee6Sartem 		}
532*0e42dee6Sartem 	}
533*0e42dee6Sartem 
534*0e42dee6Sartem 	return (B_FALSE);
535*0e42dee6Sartem }
536*0e42dee6Sartem 
537*0e42dee6Sartem /*
538*0e42dee6Sartem  * libfstyp identification failed: as a last resort, try to
539*0e42dee6Sartem  * find and run legacy /usr/lib/fs/<fsname>/fstyp commands.
540*0e42dee6Sartem  */
541*0e42dee6Sartem static void
542*0e42dee6Sartem run_legacy_cmds(int fd, char *device, int vflag)
543*0e42dee6Sartem {
544*0e42dee6Sartem 	char		*lib_dir = FSTYP_LIBFS_DIR;
545*0e42dee6Sartem 	char		*path;
546*0e42dee6Sartem 	long		name_max;
547*0e42dee6Sartem 	DIR		*dirp;
548*0e42dee6Sartem 	struct dirent	*dp_mem, *dp;
549*0e42dee6Sartem 	struct stat	st;
550*0e42dee6Sartem 	fstyp_handle_t	h;
551*0e42dee6Sartem 	int		error;
552*0e42dee6Sartem 	char		*arg1, *arg2;
553*0e42dee6Sartem 
554*0e42dee6Sartem 	if (vflag) {
555*0e42dee6Sartem 		arg1 = "-v";
556*0e42dee6Sartem 		arg2 = device;
557*0e42dee6Sartem 	} else {
558*0e42dee6Sartem 		arg1 = device;
559*0e42dee6Sartem 		arg2 = NULL;
560*0e42dee6Sartem 	}
561*0e42dee6Sartem 
562*0e42dee6Sartem 	if ((dirp = opendir(lib_dir)) == NULL) {
563*0e42dee6Sartem 		return;
564*0e42dee6Sartem 	}
565*0e42dee6Sartem 
566*0e42dee6Sartem 	name_max = pathconf(lib_dir, _PC_NAME_MAX);
567*0e42dee6Sartem 	path = calloc(1, name_max + 1);
568*0e42dee6Sartem 	dp = dp_mem = calloc(1, sizeof (struct dirent) + name_max + 1);
569*0e42dee6Sartem 	if ((path == NULL) || (dp_mem == NULL)) {
570*0e42dee6Sartem 		goto out;
571*0e42dee6Sartem 	}
572*0e42dee6Sartem 
573*0e42dee6Sartem 	while ((readdir_r(dirp, dp, &dp) == 0) && (dp != NULL)) {
574*0e42dee6Sartem 		if (dp->d_name[0] == '.') {
575*0e42dee6Sartem 			continue;
576*0e42dee6Sartem 		}
577*0e42dee6Sartem 		(void) snprintf(path, name_max, "%s/%s", lib_dir, dp->d_name);
578*0e42dee6Sartem 
579*0e42dee6Sartem 		/* it's legacy if there's no libfstyp module for it */
580*0e42dee6Sartem 		error = fstyp_init(fd, 0, path, &h);
581*0e42dee6Sartem 		if (error != FSTYP_ERR_MOD_NOT_FOUND) {
582*0e42dee6Sartem 			if (error == 0) {
583*0e42dee6Sartem 				fstyp_fini(h);
584*0e42dee6Sartem 			}
585*0e42dee6Sartem 			continue;
586*0e42dee6Sartem 		}
587*0e42dee6Sartem 
588*0e42dee6Sartem 		/* file must exist and be executable */
589*0e42dee6Sartem 		(void) snprintf(path, name_max,
590*0e42dee6Sartem 		    "%s/%s/fstyp", lib_dir, dp->d_name);
591*0e42dee6Sartem 		if ((stat(path, &st) < 0) ||
592*0e42dee6Sartem 		    ((st.st_mode & S_IXUSR) == 0)) {
593*0e42dee6Sartem 			continue;
594*0e42dee6Sartem 		}
595*0e42dee6Sartem 
596*0e42dee6Sartem 		if ((error = run_cmd(path, "fstyp", arg1, arg2)) == 0) {
597*0e42dee6Sartem 			exit(0);
598*0e42dee6Sartem 		}
599*0e42dee6Sartem 	}
600*0e42dee6Sartem 
601*0e42dee6Sartem out:
602*0e42dee6Sartem 	if (dp_mem != NULL) {
603*0e42dee6Sartem 		free(dp_mem);
604*0e42dee6Sartem 	}
605*0e42dee6Sartem 	if (path != NULL) {
606*0e42dee6Sartem 		free(path);
607*0e42dee6Sartem 	}
608*0e42dee6Sartem 	(void) closedir(dirp);
609*0e42dee6Sartem }
610*0e42dee6Sartem 
611*0e42dee6Sartem static int
612*0e42dee6Sartem run_cmd(char *path, char *arg0, char *arg1, char *arg2)
613*0e42dee6Sartem {
614*0e42dee6Sartem 	pid_t	pid;
615*0e42dee6Sartem 	int	status = 1;
616*0e42dee6Sartem 
617*0e42dee6Sartem 	pid = fork();
618*0e42dee6Sartem 	if (pid < 0) {
619*0e42dee6Sartem 		return (1);
620*0e42dee6Sartem 	} else if (pid == 0) {
621*0e42dee6Sartem 		/* child */
622*0e42dee6Sartem 		(void) execl(path, arg0, arg1, arg2, 0);
623*0e42dee6Sartem 		exit(1);
624*0e42dee6Sartem 	}
625*0e42dee6Sartem 	/* parent */
626*0e42dee6Sartem 	(void) wait(&status);
627*0e42dee6Sartem 	return (status);
628*0e42dee6Sartem }
629