4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 #include <sys/types.h>
40 #include <sys/fstyp.h>
42 #include <sys/param.h>
44 #include <sys/dktp/fdisk.h>
45 #include <sys/fs/pc_label.h>
49 #define FSTYP_LIBFS_DIR "/usr/lib/fs"
51 static const char *getmodfsname();
52 static char *getexecpathname();
53 static boolean_t
dos_to_dev(char *path
, char **devpath
, int *num
);
54 static boolean_t
find_dos_drive(int fd
, int num
, off_t
*offset
);
55 static void run_legacy_cmds(int fd
, char *device
, int vflag
);
56 static int run_cmd(char *path
, char *arg0
, char *arg1
, char *arg2
);
62 (void) fprintf(stderr
, gettext("Usage: fstyp [-av] <device>\n"));
67 main(int argc
, char **argv
)
78 nvlist_t
*attr
= NULL
;
79 fstyp_handle_t h
= NULL
;
80 const char *modfsname
;
82 int error
= FSTYP_ERR_NO_MATCH
;
84 (void) setlocale(LC_ALL
, "");
86 #if !defined(TEXT_DOMAIN)
87 #define TEXT_DOMAIN "SYS_TEST"
89 (void) textdomain(TEXT_DOMAIN
);
91 while ((c
= getopt(argc
, argv
, "av")) != -1) {
112 modfsname
= getmodfsname();
115 * Open device, find partition offset if requested
117 if (!(is_dos
= dos_to_dev(argv
[0], &devpath
, &dos_num
))) {
120 if ((fd
= open(devpath
, O_RDONLY
)) < 0) {
121 error
= FSTYP_ERR_DEV_OPEN
;
125 if (!find_dos_drive(fd
, dos_num
, &offset
)) {
126 error
= FSTYP_ERR_NO_PARTITION
;
132 * Use libfstyp to identify filesystem
134 if ((error
= fstyp_init(fd
, offset
, NULL
, &h
)) != 0) {
137 if ((error
= fstyp_ident(h
, modfsname
, &fsname
)) != 0) {
141 run_legacy_cmds(fd
, argv
[0], vflag
);
146 (void) printf("%s\n", fsname
);
149 * Output additional info if requested
152 error
= fstyp_dump(h
, stdout
, stderr
);
154 if (aflag
|| (vflag
&& (error
== FSTYP_ERR_NOP
))) {
155 if ((error
= fstyp_get_attr(h
, &attr
)) != 0) {
158 dump_nvlist(attr
, indent
);
163 (void) fprintf(stderr
, gettext("unknown_fstyp (%s)\n"),
164 fstyp_strerror(h
, error
));
172 if (devpath
!= argv
[0]) {
180 * If the executable is a fs-specific hardlink, /usr/lib/fs/<fsname>/fstyp,
181 * return that fsname; otherwise return NULL.
186 static char fsname_buf
[FSTYPSZ
+ 1];
192 if ((path
= getexecpathname()) == NULL
) {
195 if ((p
= strrchr(path
, '/')) != NULL
) {
197 if ((p
= strrchr(path
, '/')) != NULL
) {
200 if ((strcmp(path
, FSTYP_LIBFS_DIR
) == 0) &&
201 (len
> 0) && (len
< sizeof (fsname_buf
))) {
202 (void) strlcpy(fsname_buf
, p
,
203 sizeof (fsname_buf
));
213 * Return executable's absolute pathname
219 const char *execname
;
224 size
= pathconf(".", _PC_PATH_MAX
) + 1;
226 rpath
= malloc(size
);
227 cwd
= getcwd(NULL
, size
);
228 if ((path
== NULL
) || (rpath
== NULL
) || (cwd
== NULL
)) {
231 execname
= getexecname();
233 if (execname
[0] == '/') {
234 (void) snprintf(path
, size
, "%s", execname
);
236 (void) snprintf(path
, size
, "%s/%s", cwd
, execname
);
238 if (realpath(path
, rpath
) == NULL
) {
254 * Separates dos notation device spec into device and drive number
257 dos_to_dev(char *path
, char **devpath
, int *num
)
261 if ((p
= strrchr(path
, ':')) == NULL
) {
264 if ((*num
= atoi(p
+ 1)) == 0) {
268 *devpath
= getfullrawname(path
);
270 if (*devpath
!= NULL
&& **devpath
== '\0') {
274 return (*devpath
!= NULL
);
278 is_dos_drive(uchar_t type
)
280 return ((type
== DOSOS12
) || (type
== DOSOS16
) ||
281 (type
== DOSHUGE
) || (type
== FDISK_WINDOWS
) ||
282 (type
== FDISK_EXT_WIN
) || (type
== FDISK_FAT95
) ||
287 is_dos_extended(uchar_t id
)
289 return ((id
== EXTDOS
) || (id
== FDISK_EXTLBA
));
301 enum { WALK_CONTINUE
, WALK_TERMINATE
};
304 * Walk partition tables and invoke a callback for each.
307 walk_partitions(int fd
, uint32_t startsec
, off_t secsz
,
308 int (*f
)(void *, int, uint32_t, uint32_t), void *arg
)
310 uint32_t buf
[1024/4];
312 struct mboot
*mboot
= (struct mboot
*)&buf
[0];
313 struct ipart ipart
[FD_NUMPART
];
314 uint32_t sec
= startsec
;
315 uint32_t lastsec
= sec
+ 1;
322 while (sec
!= lastsec
) {
323 if (pread(fd
, buf
, bufsize
, (off_t
)sec
* secsz
) != bufsize
) {
327 if (ltohs(mboot
->signature
) != MBB_MAGIC
) {
330 bcopy(mboot
->parts
, ipart
, FD_NUMPART
* sizeof (struct ipart
));
332 for (i
= 0; i
< FD_NUMPART
; i
++) {
333 systid
= ipart
[i
].systid
;
334 relsect
= sec
+ ltohi(ipart
[i
].relsect
);
339 if (is_dos_extended(systid
) && (sec
== lastsec
)) {
340 sec
= startsec
+ ltohi(ipart
[i
].relsect
);
342 relsect
= startsec
= sec
;
347 if (valid
&& f(arg
, ipart
[i
].systid
, relsect
,
348 ltohi(ipart
[i
].numsect
)) == WALK_TERMINATE
) {
356 find_dos_drive_cb(void *arg
, int systid
, uint32_t relsect
, uint32_t numsect
)
358 struct part_find_s
*p
= arg
;
360 if (is_dos_drive(systid
)) {
361 if (++p
->count
== p
->num
) {
362 p
->r_relsect
= relsect
;
363 p
->r_numsect
= numsect
;
364 p
->r_systid
= systid
;
365 return (WALK_TERMINATE
);
369 return (WALK_CONTINUE
);
373 * Given a dos drive number, return its relative offset in the drive.
376 find_dos_drive(int fd
, int num
, off_t
*offset
)
380 struct part_find_s p
= { 0, 0, 0, 0, 0, 0 };
385 * It is possible that the media we are dealing with can have different
386 * sector size than the default 512 bytes. Query the driver and check
387 * whether the media has different sector size.
389 if (ioctl(fd
, DKIOCGMEDIAINFO
, &mi
) < 0)
392 secsz
= mi
.dki_lbsize
;
395 walk_partitions(fd
, 0, secsz
, find_dos_drive_cb
, &p
);
396 if (p
.count
== num
) {
397 *offset
= secsz
* (off_t
)p
.r_relsect
;
406 * libfstyp identification failed: as a last resort, try to
407 * find and run legacy /usr/lib/fs/<fsname>/fstyp commands.
410 run_legacy_cmds(int fd
, char *device
, int vflag
)
412 char *lib_dir
= FSTYP_LIBFS_DIR
;
416 struct dirent
*dp_mem
, *dp
;
430 if ((dirp
= opendir(lib_dir
)) == NULL
) {
434 name_max
= pathconf(lib_dir
, _PC_NAME_MAX
);
435 path
= calloc(1, name_max
+ 1);
436 dp
= dp_mem
= calloc(1, sizeof (struct dirent
) + name_max
+ 1);
437 if ((path
== NULL
) || (dp_mem
== NULL
)) {
441 while ((readdir_r(dirp
, dp
, &dp
) == 0) && (dp
!= NULL
)) {
442 if (dp
->d_name
[0] == '.') {
445 (void) snprintf(path
, name_max
, "%s/%s", lib_dir
, dp
->d_name
);
447 /* it's legacy if there's no libfstyp module for it */
448 error
= fstyp_init(fd
, 0, path
, &h
);
449 if (error
!= FSTYP_ERR_MOD_NOT_FOUND
) {
456 /* file must exist and be executable */
457 (void) snprintf(path
, name_max
,
458 "%s/%s/fstyp", lib_dir
, dp
->d_name
);
459 if ((stat(path
, &st
) < 0) ||
460 ((st
.st_mode
& S_IXUSR
) == 0)) {
464 if ((error
= run_cmd(path
, "fstyp", arg1
, arg2
)) == 0) {
470 if (dp_mem
!= NULL
) {
476 (void) closedir(dirp
);
480 run_cmd(char *path
, char *arg0
, char *arg1
, char *arg2
)
488 } else if (pid
== 0) {
490 (void) execl(path
, arg0
, arg1
, arg2
, 0);
494 (void) wait(&status
);